main(int argc, char** argv) { if (argc < 2) { fprintf(stderr, "Usage: %s <file>\n", argv[0]); exit(1); } u_int32_t verbosity = 0 /* MP4_DETAILS_ALL */; MP4FileHandle mp4File = MP4Create(argv[1], verbosity); if (!mp4File) { exit(1); } MP4TrackId urlTrackId = MP4AddTrack(mp4File, "URLF"); printf("urlTrackId %d\n", urlTrackId); u_int8_t i; char url[128]; for (i = 1; i <= 5; i++) { sprintf(url, "http://server.com/foo/bar%u.html", i); MP4WriteSample(mp4File, urlTrackId, (u_int8_t*)url, strlen(url) + 1, (MP4Duration)i); } MP4Close(mp4File); mp4File = MP4Read(argv[1], verbosity); // check that we can find the track again urlTrackId = MP4FindTrackId(mp4File, 0, "URLF"); printf("urlTrackId %d\n", urlTrackId); for (i = 1; i <= 5; i++) { u_int8_t* pSample = NULL; u_int32_t sampleSize = 0; MP4Duration duration; bool rc; rc = MP4ReadSample(mp4File, urlTrackId, i, &pSample, &sampleSize, NULL, &duration); if (rc) { printf("Sample %i duration "D64": %s\n", i, duration, pSample); free(pSample); } else { printf("Couldn't read sample %i\n", i); } } MP4Close(mp4File); exit(0); }
int covert_aac_to_mp4(char *inputFileName, char *mp4FileName) { int Mp4TimeScale = 90000; int allMpeg4Streams = 0; MP4FileHandle mp4File; FILE* inFile; const char *type; MP4TrackId createdTrackId = MP4_INVALID_TRACK_ID; mp4File = MP4Create(mp4FileName, 0, 0); if (mp4File) { MP4SetTimeScale(mp4File, Mp4TimeScale); } else { return 1; } inFile = fopen(inputFileName, "rb"); if (inFile == NULL) { MP4Close(mp4File); return 2; } createdTrackId = AacCreator(mp4File, inFile); if (createdTrackId == MP4_INVALID_TRACK_ID) { fclose(inFile); MP4Close(mp4File); return 3; } type = MP4GetTrackType(mp4File, createdTrackId); if (!strcmp(type, MP4_AUDIO_TRACK_TYPE)) { allMpeg4Streams &= (MP4GetTrackEsdsObjectTypeId(mp4File, createdTrackId) == MP4_MPEG4_AUDIO_TYPE); } if (inFile) { fclose(inFile); } MP4Close(mp4File); MP4MakeIsmaCompliant(mp4FileName, 0, allMpeg4Streams); return 0; }
/** \fn close \brief Cleanup is done in the dtor */ bool muxerMp4v2::close(void) { if(handle) { MP4Close(handle,ADM_MP4_OPTIONS_CLOSE); //#warning run MP4Optimize } handle=NULL; if(audioTrackIds) delete [] audioTrackIds; audioTrackIds=NULL; if(audioPackets) delete [] audioPackets; audioPackets=NULL; for(int i=0;i<2;i++) { if(videoBuffer[i]) delete [] videoBuffer[i]; videoBuffer[i]=NULL; } if(scratchBuffer) { delete [] scratchBuffer; scratchBuffer=NULL; } ADM_info("[Mp4v2Muxer] Closing\n"); return true; }
void Mp4Encoder::Stop() { if (m_hMp4File) { MP4Close(m_hMp4File); m_hMp4File = NULL; } }
void mpeg_video_recorder::StopRecording(){ if (MP4_IS_VALID_FILE_HANDLE(m_hMp4FileHandle)){ MP4Close(m_hMp4FileHandle); } m_IsRecording = false; }
void MP4Encoder::CloseMP4File(MP4FileHandle hMp4File) { if(hMp4File) { MP4Close(hMp4File); hMp4File = NULL; } }
void SoundSourceM4A::close() { closeDecoder(); m_sampleBuffer.reset(); m_inputBuffer.clear(); if (MP4_INVALID_FILE_HANDLE != m_hFile) { MP4Close(m_hFile); m_hFile = MP4_INVALID_FILE_HANDLE; } }
~MP4Reader() { if (pSeqHeaders || pSeqHeaderSize || pPictHeaders || pPictHeaderSize) { MP4FreeH264SeqPictHeaders(pSeqHeaders, pSeqHeaderSize, pPictHeaders, pPictHeaderSize); } if (handle != MP4_INVALID_FILE_HANDLE) MP4Close(handle); if (video_sample) delete[] video_sample; }
CMp4File::~CMp4File (void) { MP4Close(m_mp4file); m_mp4file = NULL; if (m_file_mutex) { SDL_DestroyMutex(m_file_mutex); m_file_mutex = NULL; } }
void SoundSourceM4A::close() { if (m_hDecoder) { NeAACDecClose(m_hDecoder); m_hDecoder = NULL; } if (MP4_INVALID_FILE_HANDLE != m_hFile) { MP4Close(m_hFile); m_hFile = MP4_INVALID_FILE_HANDLE; } m_inputBuffer.clear(); }
AacPcm::~AacPcm() { if(mp4File) MP4Close(mp4File); if(aacFile) fclose(aacFile); if(hDecoder) faacDecClose(hDecoder); FREE_ARRAY(buffer); FREE_ARRAY(seek_table); }
int MP4Streamer::Close() { Log(">MP4 Close\n"); //Lock pthread_mutex_lock(&mutex); //Change state opened = false; //If we have been opened if (mp4!=MP4_INVALID_FILE_HANDLE) // Close file MP4Close(mp4); //Unset handler mp4 = MP4_INVALID_FILE_HANDLE; //It it waas playing if (playing) { //Not playing playing = 0; //Signal pthread_cond_signal(&cond); //Get running thread DWORD running = thread; //Clean thread thread = NULL; //Unlock pthread_mutex_unlock(&mutex); //Check thread if (running) //Wait for running thread pthread_join(running,NULL); } else { //Unlock pthread_mutex_unlock(&mutex); } Log("<MP4 Close\n"); return 1; }
void CAVInfo::ReadMP4(const char *file) { MP4FileHandle mp4File = MP4Read(file, MP4_DETAILS_ERROR); if ( !mp4File ) { return; } uint32_t vsize; uint8_t *value; char *pname = "moov.uuid.data"; MP4GetBytesProperty(mp4File, pname, &value, &vsize); if ( vsize ) { MP4_moov_uuid_parse(value, vsize, m_title); free(value); } MP4Close(mp4File); }
extern "C" char* MP4FileInfo( const char* fileName, MP4TrackId trackId) { MP4FileHandle mp4File = MP4Read(fileName); if (!mp4File) { return NULL; } char* info = MP4Info(mp4File, trackId); MP4Close(mp4File); return info; // caller should free this }
int32_t Mp4FileDefaultAudio(const char* fileName) { MP4FileHandle mp4File = MP4Read(fileName); if (mp4File == MP4_INVALID_FILE_HANDLE) { return -1; } MP4TrackId trackId = MP4FindTrackId(mp4File, 0, MP4_AUDIO_TRACK_TYPE); MP4Close(mp4File); if (trackId == MP4_INVALID_TRACK_ID) { return -1; } return trackId; }
int CMP4Tag::ReadMp4Tag(char *Filename) { MP4FileHandle MP4File; if(!(MP4File=MP4Read(Filename, 0))) { char buf[25+MAX_PATH+1]; sprintf(buf,"ReadMp4Tag: can't open \"%s\"",Filename); MessageBox(NULL,buf,NULL,MB_OK); return 1; } FREE_ARRAY(copyright); MP4GetMetadataTool(MP4File, ©right); FREE_ARRAY(artist); MP4GetMetadataArtist(MP4File, &artist); FREE_ARRAY(writer); MP4GetMetadataWriter(MP4File, &writer); FREE_ARRAY(title); MP4GetMetadataName(MP4File, &title); FREE_ARRAY(album); MP4GetMetadataAlbum(MP4File, &album); MP4GetMetadataTrack(MP4File, (unsigned __int16 *)&trackno, (unsigned __int16 *)&ntracks); MP4GetMetadataDisk(MP4File, (unsigned __int16 *)&discno, (unsigned __int16 *)&ndiscs); MP4GetMetadataCompilation(MP4File, (unsigned __int8 *)&compilation); FREE_ARRAY(year); MP4GetMetadataYear(MP4File, &year); FREE_ARRAY(genre); MP4GetMetadataGenre(MP4File, &genre); FREE_ARRAY(comment); MP4GetMetadataComment(MP4File, &comment); FREE_ARRAY(art.data); MP4GetMetadataCoverArt(MP4File, (unsigned __int8 **)&art.data, (u_int32_t *)&art.size); MP4Close(MP4File); /* FILE *f=fopen("D:\\prova.jpg","wb"); fwrite(artFile,1,artSize,f); fclose(f);*/ return 0; }
bool Strip_Tag(LPCSTR filename) { // TODO: // remove tag from file. // do whatever is need to remove the supported tag from filename // return true for successfull strip, false for failure MP4FileHandle file; file = MP4Modify(filename, 0, 0); if (file == MP4_INVALID_FILE_HANDLE) return false; MP4MetadataDelete(file); MP4Close(file); return true; }
static void aac_free (DB_fileinfo_t *_info) { aac_info_t *info = (aac_info_t *)_info; if (info) { if (info->file) { deadbeef->fclose (info->file); } if (info->mp4file) { #ifdef USE_MP4FF mp4ff_close (info->mp4file); #else MP4Close (info->mp4file); #endif } if (info->dec) { NeAACDecClose (info->dec); } free (info); } }
static switch_status_t mp4_file_close(switch_file_handle_t *handle) { mp4_file_context_t *context = handle->private_info; if (context->fd) { MP4Close(context->fd, 0); context->fd = NULL; } if (switch_core_codec_ready(&context->audio_codec)) switch_core_codec_destroy(&context->audio_codec); if (switch_core_codec_ready(&context->video_codec)) switch_core_codec_destroy(&context->video_codec); if (context->timer.interval) { switch_core_timer_destroy(&context->timer); } switch_img_free(&context->last_img); switch_buffer_destroy(&context->buf); return SWITCH_STATUS_SUCCESS; }
int encoder_uninitialize(unsigned long id) { if(!pestreams[id].firstwrite) { faacEncClose(pestreams[id].enchandle); sys_mem_free(pestreams[id].floatbuffer); sys_mem_free(pestreams[id].obuffer); sys_mem_free(pestreams[id].cachebuffer); if(!pestreams[id].ismp4) { sys_file_close(pestreams[id].fhandle); }else{ MP4Close(pestreams[id].mp4file); } pestreams[id].firstwrite = 1; } return 1; }
int aac_decode(aac_dec_opt *opt) { int result; int def_srate = 0; int outfile_set = 0; int mp4file = 0; char *fnp; char audioFileName[MAX_PATH]; MP4FileHandle infile; /* point to the specified file name */ strcpy(audioFileName, opt->filename); fnp = (char *)strrchr(audioFileName,'.'); if (fnp) fnp[0] = '\0'; strcat(audioFileName, file_ext[opt->file_type]); mp4file = 1; infile = MP4Read(audioFileName, 0); if (!infile) mp4file = 0; if (infile) MP4Close(infile); if (mp4file) { result = decodeMP4file(audioFileName, opt); } else { result = decodeAACfile(audioFileName, def_srate, opt); } return 0; }
int main(int argc, char** argv) { static struct option long_options[] = { { "help", 0, 0, OPT_HELP }, { "version", 0, 0, OPT_VERSION }, { "album", 1, 0, OPT_ALBUM }, { "artist", 1, 0, OPT_ARTIST }, { "comment", 1, 0, OPT_COMMENT }, { "disk", 1, 0, OPT_DISK }, { "disks", 1, 0, OPT_DISKS }, { "genre", 1, 0, OPT_GENRE }, { "song", 1, 0, OPT_SONG }, { "tempo", 1, 0, OPT_TEMPO }, { "track", 1, 0, OPT_TRACK }, { "tracks", 1, 0, OPT_TRACKS }, { "writer", 1, 0, OPT_WRITER }, { "year", 1, 0, OPT_YEAR }, { NULL, 0, 0, 0 } }; /* Sparse arrays of tag data: some space is wasted, but it's more convenient to say tags[OPT_SONG] than to enumerate all the metadata types (again) as a struct. */ char *tags[UCHAR_MAX] = { 0 }; int nums[UCHAR_MAX] = { 0 }; /* Any modifications requested? */ int mods = 0; /* Option-processing loop. */ int c = getopt_long_only(argc, argv, OPT_STRING, long_options, NULL); while (c != -1) { int r = 2; switch(c) { /* getopt() returns '?' if there was an error. It already printed the error message, so just return. */ case '?': return 1; /* Help and version requests handled here. */ case OPT_HELP: fprintf(stderr, "usage %s %s", argv[0], help_text); return 0; case OPT_VERSION: fprintf(stderr, "%s - %s version %s\n", argv[0], MPEG4IP_PACKAGE, MPEG4IP_VERSION); return 0; /* Numeric arguments: convert them using sscanf(). */ case OPT_DISK: case OPT_DISKS: case OPT_TRACK: case OPT_TRACKS: case OPT_TEMPO: r = sscanf(optarg, "%d", &nums[c]); if (r < 1) { fprintf(stderr, "%s: option requires numeric argument -- %c\n", argv[0], c); return 2; } /* Break not, lest ye be broken. :) */ /* All arguments: all valid options end up here, and we just stuff the string pointer into the tags[] array. */ default: tags[c] = optarg; mods++; } /* end switch */ c = getopt_long_only(argc, argv, OPT_STRING, long_options, NULL); } /* end while */ /* Check that we have at least one non-option argument */ if ((argc - optind) < 1) { fprintf(stderr, "%s: You must specify at least one MP4 file.\n", argv[0]); fprintf(stderr, "usage %s %s", argv[0], help_text); return 3; } /* Check that we have at least one requested modification. Probably it's useful instead to print the metadata if no modifications are requested? */ if (!mods) { fprintf(stderr, "%s: You must specify at least one tag modification.\n", argv[0]); fprintf(stderr, "usage %s %s", argv[0], help_text); return 4; } /* Loop through the non-option arguments, and modify the tags as requested. */ while (optind < argc) { char *mp4 = argv[optind++]; MP4FileHandle h = MP4Modify(mp4); if (h == MP4_INVALID_FILE_HANDLE) { fprintf(stderr, "Could not open '%s'... aborting\n", mp4); return 5; } /* Track/disk numbers need to be set all at once, but we'd like to allow users to just specify -T 12 to indicate that all existing track numbers are out of 12. This means we need to look up the current info if it is not being set. */ uint16_t n0, m0, n1, m1; if (tags[OPT_TRACK] || tags[OPT_TRACKS]) { MP4GetMetadataTrack(h, &n0, &m0); n1 = tags[OPT_TRACK]? nums[OPT_TRACK] : n0; m1 = tags[OPT_TRACKS]? nums[OPT_TRACKS] : m0; MP4SetMetadataTrack(h, n1, m1); } if (tags[OPT_DISK] || tags[OPT_DISKS]) { MP4GetMetadataDisk(h, &n0, &m0); n1 = tags[OPT_DISK]? nums[OPT_DISK] : n0; m1 = tags[OPT_DISKS]? nums[OPT_DISKS] : m0; MP4SetMetadataDisk(h, n1, m1); } /* Set the other relevant attributes */ for (int i = 0; i < UCHAR_MAX; i++) { if (tags[i]) { switch(i) { case OPT_ALBUM: MP4SetMetadataAlbum(h, tags[i]); break; case OPT_ARTIST: MP4SetMetadataArtist(h, tags[i]); break; case OPT_COMMENT: MP4SetMetadataComment(h, tags[i]); break; case OPT_GENRE: MP4SetMetadataGenre(h, tags[i]); break; case OPT_SONG: MP4SetMetadataName(h, tags[i]); break; case OPT_WRITER: MP4SetMetadataWriter(h, tags[i]); break; case OPT_YEAR: MP4SetMetadataYear(h, tags[i]); break; case OPT_TEMPO: MP4SetMetadataTempo(h, nums[i]); break; } } } MP4Close(h); } /* end while optind < argc */ return 0; }
void Context::close() { if (!isOpen()) return; MP4Close(fh); }
static switch_status_t mp4_file_open(switch_file_handle_t *handle, const char *path) { mp4_file_context_t *context; char *ext; unsigned int flags = 0; const char *tmp = NULL; if ((ext = strrchr(path, '.')) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Format\n"); return SWITCH_STATUS_GENERR; } ext++; if ((context = switch_core_alloc(handle->memory_pool, sizeof(mp4_file_context_t))) == 0) { return SWITCH_STATUS_MEMERR; } memset(context, 0, sizeof(mp4_file_context_t)); context->offset = -100; if (handle->params && (tmp = switch_event_get_header(handle->params, "mp4v2_video_offset"))) { context->offset = atoi(tmp); } context->audio_type = MP4_ULAW_AUDIO_TYPE; // default if (handle->params && (tmp = switch_event_get_header(handle->params, "mp4v2_audio_codec"))) { if (!strcasecmp(tmp, "PCMU")) { context->audio_type = MP4_ULAW_AUDIO_TYPE; } else if (!strcasecmp(tmp, "MP3")) { context->audio_type = MP4_MP3_AUDIO_TYPE; } else if (!strcasecmp(tmp, "AAC")) { context->audio_type = MP4_MPEG4_AUDIO_TYPE; } else if (!strcasecmp(tmp, "L16")) { context->audio_type = MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE; } } switch_mutex_init(&context->mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { flags |= SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE; if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND) || switch_test_flag(handle, SWITCH_FILE_WRITE_OVER)) { flags |= SWITCH_FOPEN_READ; } else { flags |= SWITCH_FOPEN_TRUNCATE; } } if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) { flags |= SWITCH_FOPEN_READ; } if ((context->fd = MP4CreateEx(path, 0, 1, 1, NULL, 0, NULL, 0)) == MP4_INVALID_FILE_HANDLE) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error opening file %s\n", path); return SWITCH_STATUS_GENERR; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sample rate: %d, channels: %d\n", handle->samplerate, handle->channels); if (context->audio_type == MP4_ULAW_AUDIO_TYPE) { context->audio = MP4AddULawAudioTrack(context->fd, handle->samplerate); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.ulaw.channels", handle->channels); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.ulaw.sampleSize", 8); } else if (context->audio_type == MP4_MP3_AUDIO_TYPE) { // handle->samplerate = 44100; context->audio = MP4AddAudioTrack(context->fd, handle->samplerate, handle->samplerate, MP4_MP3_AUDIO_TYPE); MP4SetTrackName(context->fd, context->audio, ".mp3"); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.mp4a.channels", handle->channels); // MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd..mp3.channels", handle->channels); } else if (context->audio_type == MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE) { context->audio = MP4AddAudioTrack(context->fd, handle->samplerate, handle->samplerate, MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE); MP4SetTrackName(context->fd, context->audio, "lpcm"); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.mp4a.channels", handle->channels); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.lpcm.channels", handle->channels); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.lpcm.sampleSize", 16); } else if (context->audio_type == MP4_MPEG4_AUDIO_TYPE) { /* AAC object types */ #define AAC_MAIN 1 #define AAC_LOW 2 #define AAC_SSR 3 #define AAC_LTP 4 uint16_t info = 0; info |= AAC_LOW << 11; // aacObjectType (5bit) info |= get_aac_sample_rate_index(handle->samplerate) << 7; //(4bit) info |= handle->channels << 3; //(4bit) info = htons(info); context->audio = MP4AddAudioTrack(context->fd, handle->samplerate, handle->samplerate, MP4_MPEG4_AUDIO_TYPE); MP4SetTrackESConfiguration(context->fd, context->audio, (uint8_t *)&info, sizeof(info)); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.mp4a.channels", handle->channels); } handle->format = 0; handle->sections = 0; handle->seekable = 0; handle->speed = 0; handle->pos = 0; handle->private_info = context; context->pool = handle->memory_pool; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening File [%s] %dhz %s\n", path, handle->samplerate, switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO) ? " with VIDEO" : ""); if (switch_core_codec_init(&context->audio_codec, get_audio_codec_name(context->audio_type), NULL, NULL, handle->samplerate, 20,//ms handle->channels, SWITCH_CODEC_FLAG_ENCODE, NULL, handle->memory_pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio Codec Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Audio Codec Activation Fail\n"); goto end; } if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) { if (switch_core_codec_init(&context->video_codec, "H264", NULL, NULL, 90000, 0,//ms 1, SWITCH_CODEC_FLAG_ENCODE, NULL, handle->memory_pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video Codec H264 Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Video Codec H264 Activation Fail\n"); goto end; } } if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { MP4SetAudioProfileLevel(context->fd, 0x7F); } switch_buffer_create_dynamic(&context->buf, 512, 512, 1024000); return SWITCH_STATUS_SUCCESS; end: if (context->fd) { MP4Close(context->fd, 0); context->fd = NULL; } return SWITCH_STATUS_FALSE; }
int main(int argc, char *argv[]) { int frames, currentFrame; faacEncHandle hEncoder; pcmfile_t *infile = NULL; unsigned long samplesInput, maxBytesOutput, totalBytesWritten=0; faacEncConfigurationPtr myFormat; unsigned int mpegVersion = MPEG2; unsigned int objectType = LOW; unsigned int useMidSide = 1; static unsigned int useTns = DEFAULT_TNS; enum container_format container = NO_CONTAINER; int optimizeFlag = 0; enum stream_format stream = ADTS_STREAM; int cutOff = -1; int bitRate = 0; unsigned long quantqual = 0; int chanC = 3; int chanLF = 4; char *audioFileName = NULL; char *aacFileName = NULL; char *aacFileExt = NULL; int aacFileNameGiven = 0; float *pcmbuf; int *chanmap = NULL; unsigned char *bitbuf; int samplesRead = 0; const char *dieMessage = NULL; int rawChans = 0; // disabled by default int rawBits = 16; int rawRate = 44100; int rawEndian = 1; int shortctl = SHORTCTL_NORMAL; FILE *outfile = NULL; #ifdef HAVE_LIBMP4V2 MP4FileHandle MP4hFile = MP4_INVALID_FILE_HANDLE; MP4TrackId MP4track = 0; unsigned int ntracks = 0, trackno = 0; unsigned int ndiscs = 0, discno = 0; u_int8_t compilation = 0; const char *artist = NULL, *title = NULL, *album = NULL, *year = NULL, *genre = NULL, *comment = NULL, *writer = NULL; u_int8_t *art = NULL; u_int64_t artSize = 0; u_int64_t total_samples = 0; u_int64_t encoded_samples = 0; unsigned int delay_samples; unsigned int frameSize; #endif char *faac_id_string; char *faac_copyright_string; #ifndef _WIN32 // install signal handler signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); #endif // get faac version if (faacEncGetVersion(&faac_id_string, &faac_copyright_string) == FAAC_CFG_VERSION) { fprintf(stderr, "Freeware Advanced Audio Coder\nFAAC %s\n\n", faac_id_string); } else { fprintf(stderr, __FILE__ "(%d): wrong libfaac version\n", __LINE__); return 1; } /* begin process command line */ progName = argv[0]; while (1) { static struct option long_options[] = { { "help", 0, 0, 'h'}, { "long-help", 0, 0, 'H'}, { "raw", 0, 0, 'r'}, { "no-midside", 0, 0, NO_MIDSIDE_FLAG}, { "cutoff", 1, 0, 'c'}, { "quality", 1, 0, 'q'}, { "pcmraw", 0, 0, 'P'}, { "pcmsamplerate", 1, 0, 'R'}, { "pcmsamplebits", 1, 0, 'B'}, { "pcmchannels", 1, 0, 'C'}, { "shortctl", 1, 0, SHORTCTL_FLAG}, { "tns", 0, 0, TNS_FLAG}, { "no-tns", 0, 0, NO_TNS_FLAG}, { "mpeg-version", 1, 0, MPEGVERS_FLAG}, { "obj-type", 1, 0, OBJTYPE_FLAG}, { "license", 0, 0, 'L'}, #ifdef HAVE_LIBMP4V2 { "createmp4", 0, 0, 'w'}, { "optimize", 0, 0, 's'}, { "artist", 1, 0, ARTIST_FLAG}, { "title", 1, 0, TITLE_FLAG}, { "album", 1, 0, ALBUM_FLAG}, { "track", 1, 0, TRACK_FLAG}, { "disc", 1, 0, DISC_FLAG}, { "genre", 1, 0, GENRE_FLAG}, { "year", 1, 0, YEAR_FLAG}, { "cover-art", 1, 0, COVER_ART_FLAG}, { "comment", 1, 0, COMMENT_FLAG}, { "writer", 1, 0, WRITER_FLAG}, { "compilation", 0, 0, COMPILATION_FLAG}, #endif { "pcmswapbytes", 0, 0, 'X'}, { 0, 0, 0, 0} }; int c = -1; int option_index = 0; c = getopt_long(argc, argv, "Hhb:m:o:rnc:q:PR:B:C:I:X" #ifdef HAVE_LIBMP4V2 "ws" #endif ,long_options, &option_index); if (c == -1) break; if (!c) { dieMessage = usage; break; } switch (c) { case 'o': { int l = strlen(optarg); aacFileName = malloc(l+1); memcpy(aacFileName, optarg, l); aacFileName[l] = '\0'; aacFileNameGiven = 1; } break; case 'r': { stream = RAW_STREAM; break; } case NO_MIDSIDE_FLAG: { useMidSide = 0; break; } case 'c': { unsigned int i; if (sscanf(optarg, "%u", &i) > 0) { cutOff = i; } break; } case 'b': { unsigned int i; if (sscanf(optarg, "%u", &i) > 0) { bitRate = 1000 * i; } break; } case 'q': { unsigned int i; if (sscanf(optarg, "%u", &i) > 0) { if (i > 0 && i < 1000) quantqual = i; } break; } case 'I': sscanf(optarg, "%d,%d", &chanC, &chanLF); break; case 'P': rawChans = 2; // enable raw input break; case 'R': { unsigned int i; if (sscanf(optarg, "%u", &i) > 0) { rawRate = i; rawChans = (rawChans > 0) ? rawChans : 2; } break; } case 'B': { unsigned int i; if (sscanf(optarg, "%u", &i) > 0) { if (i > 32) i = 32; if (i < 8) i = 8; rawBits = i; rawChans = (rawChans > 0) ? rawChans : 2; } break; } case 'C': { unsigned int i; if (sscanf(optarg, "%u", &i) > 0) rawChans = i; break; } #ifdef HAVE_LIBMP4V2 case 'w': container = MP4_CONTAINER; break; case 's': optimizeFlag = 1; break; case ARTIST_FLAG: artist = optarg; break; case WRITER_FLAG: writer = optarg; break; case TITLE_FLAG: title = optarg; break; case ALBUM_FLAG: album = optarg; break; case TRACK_FLAG: sscanf(optarg, "%d/%d", &trackno, &ntracks); break; case DISC_FLAG: sscanf(optarg, "%d/%d", &discno, &ndiscs); break; case COMPILATION_FLAG: compilation = 0x1; break; case GENRE_FLAG: genre = optarg; break; case YEAR_FLAG: year = optarg; break; case COMMENT_FLAG: comment = optarg; break; case COVER_ART_FLAG: { FILE *artFile = fopen(optarg, "rb"); if(artFile) { u_int64_t r; fseek(artFile, 0, SEEK_END); artSize = ftell(artFile); art = malloc(artSize); fseek(artFile, 0, SEEK_SET); clearerr(artFile); r = fread(art, artSize, 1, artFile); if (r != 1) { dieMessage = "Error reading cover art file!\n"; free(art); art = NULL; } else if (artSize < 12 || !check_image_header(art)) { /* the above expression checks the image signature */ dieMessage = "Unsupported cover image file format!\n"; free(art); art = NULL; } fclose(artFile); } else { dieMessage = "Error opening cover art file!\n"; } break; } #endif case SHORTCTL_FLAG: shortctl = atoi(optarg); break; case TNS_FLAG: useTns = 1; break; case NO_TNS_FLAG: useTns = 0; break; case MPEGVERS_FLAG: mpegVersion = atoi(optarg); switch(mpegVersion) { case 2: mpegVersion = MPEG2; break; case 4: mpegVersion = MPEG4; break; default: dieMessage = "Unrecognised MPEG version!\n"; } break; #if 0 case OBJTYPE_FLAG: if (!strcasecmp(optarg, "LC")) objectType = LOW; else if (!strcasecmp(optarg, "Main")) objectType = MAIN; else if (!strcasecmp(optarg, "LTP")) { mpegVersion = MPEG4; objectType = LTP; } else dieMessage = "Unrecognised object type!\n"; break; #endif case 'L': fprintf(stderr, faac_copyright_string); dieMessage = license; break; case 'X': rawEndian = 0; break; case 'H': dieMessage = long_help; break; case 'h': dieMessage = short_help; break; case '?': default: dieMessage = usage; break; } } /* check that we have at least one non-option arguments */ if (!dieMessage && (argc - optind) > 1 && aacFileNameGiven) dieMessage = "Cannot encode several input files to one output file.\n"; if (argc - optind < 1 || dieMessage) { fprintf(stderr, dieMessage ? dieMessage : usage, progName, progName, progName, progName); return 1; } while (argc - optind > 0) { /* get the input file name */ audioFileName = argv[optind++]; /* generate the output file name, if necessary */ if (!aacFileNameGiven) { char *t = strrchr(audioFileName, '.'); int l = t ? strlen(audioFileName) - strlen(t) : strlen(audioFileName); #ifdef HAVE_LIBMP4V2 aacFileExt = container == MP4_CONTAINER ? ".m4a" : ".aac"; #else aacFileExt = ".aac"; #endif aacFileName = malloc(l+1+4); memcpy(aacFileName, audioFileName, l); memcpy(aacFileName + l, aacFileExt, 4); aacFileName[l+4] = '\0'; } else { aacFileExt = strrchr(aacFileName, '.'); if (aacFileExt && (!strcmp(".m4a", aacFileExt) || !strcmp(".m4b", aacFileExt) || !strcmp(".mp4", aacFileExt))) #ifndef HAVE_LIBMP4V2 fprintf(stderr, "WARNING: MP4 support unavailable!\n"); #else container = MP4_CONTAINER; #endif } /* open the audio input file */ if (rawChans > 0) // use raw input { infile = wav_open_read(audioFileName, 1); if (infile) { infile->bigendian = rawEndian; infile->channels = rawChans; infile->samplebytes = rawBits / 8; infile->samplerate = rawRate; infile->samples /= (infile->channels * infile->samplebytes); } } else // header input infile = wav_open_read(audioFileName, 0); if (infile == NULL) { fprintf(stderr, "Couldn't open input file %s\n", audioFileName); return 1; } /* open the encoder library */ hEncoder = faacEncOpen(infile->samplerate, infile->channels, &samplesInput, &maxBytesOutput); #ifdef HAVE_LIBMP4V2 if (container != MP4_CONTAINER && (ntracks || trackno || artist || title || album || year || art || genre || comment || discno || ndiscs || writer || compilation)) { fprintf(stderr, "Metadata requires MP4 output!\n"); return 1; } if (container == MP4_CONTAINER) { mpegVersion = MPEG4; stream = RAW_STREAM; } frameSize = samplesInput/infile->channels; delay_samples = frameSize; // encoder delay 1024 samples #endif pcmbuf = (float *)malloc(samplesInput*sizeof(float)); bitbuf = (unsigned char*)malloc(maxBytesOutput*sizeof(unsigned char)); chanmap = mkChanMap(infile->channels, chanC, chanLF); if (chanmap) { fprintf(stderr, "Remapping input channels: Center=%d, LFE=%d\n", chanC, chanLF); } if (cutOff <= 0) { if (cutOff < 0) // default cutOff = 0; else // disabled cutOff = infile->samplerate / 2; } if (cutOff > (infile->samplerate / 2)) cutOff = infile->samplerate / 2; /* put the options in the configuration struct */ myFormat = faacEncGetCurrentConfiguration(hEncoder); myFormat->aacObjectType = objectType; myFormat->mpegVersion = mpegVersion; myFormat->useTns = useTns; switch (shortctl) { case SHORTCTL_NOSHORT: fprintf(stderr, "disabling short blocks\n"); myFormat->shortctl = shortctl; break; case SHORTCTL_NOLONG: fprintf(stderr, "disabling long blocks\n"); myFormat->shortctl = shortctl; break; } if (infile->channels >= 6) myFormat->useLfe = 1; myFormat->allowMidside = useMidSide; if (bitRate) myFormat->bitRate = bitRate / infile->channels; myFormat->bandWidth = cutOff; if (quantqual > 0) myFormat->quantqual = quantqual; myFormat->outputFormat = stream; myFormat->inputFormat = FAAC_INPUT_FLOAT; if (!faacEncSetConfiguration(hEncoder, myFormat)) { fprintf(stderr, "Unsupported output format!\n"); #ifdef HAVE_LIBMP4V2 if (container == MP4_CONTAINER) MP4Close(MP4hFile); #endif return 1; } #ifdef HAVE_LIBMP4V2 /* initialize MP4 creation */ if (container == MP4_CONTAINER) { unsigned char *ASC = 0; unsigned long ASCLength = 0; char *version_string; #ifdef MP4_CREATE_EXTENSIBLE_FORMAT /* hack to compile against libmp4v2 >= 1.0RC3 * why is there no version identifier in mp4.h? */ MP4hFile = MP4Create(aacFileName, MP4_DETAILS_ERROR, 0); #else MP4hFile = MP4Create(aacFileName, MP4_DETAILS_ERROR, 0, 0); #endif if (!MP4_IS_VALID_FILE_HANDLE(MP4hFile)) { fprintf(stderr, "Couldn't create output file %s\n", aacFileName); return 1; } MP4SetTimeScale(MP4hFile, 90000); MP4track = MP4AddAudioTrack(MP4hFile, infile->samplerate, MP4_INVALID_DURATION, MP4_MPEG4_AUDIO_TYPE); MP4SetAudioProfileLevel(MP4hFile, 0x0F); faacEncGetDecoderSpecificInfo(hEncoder, &ASC, &ASCLength); MP4SetTrackESConfiguration(MP4hFile, MP4track, ASC, ASCLength); free(ASC); /* set metadata */ version_string = malloc(strlen(faac_id_string) + 6); strcpy(version_string, "FAAC "); strcpy(version_string + 5, faac_id_string); MP4SetMetadataTool(MP4hFile, version_string); free(version_string); if (artist) MP4SetMetadataArtist(MP4hFile, artist); if (writer) MP4SetMetadataWriter(MP4hFile, writer); if (title) MP4SetMetadataName(MP4hFile, title); if (album) MP4SetMetadataAlbum(MP4hFile, album); if (trackno > 0) MP4SetMetadataTrack(MP4hFile, trackno, ntracks); if (discno > 0) MP4SetMetadataDisk(MP4hFile, discno, ndiscs); if (compilation) MP4SetMetadataCompilation(MP4hFile, compilation); if (year) MP4SetMetadataYear(MP4hFile, year); if (genre) MP4SetMetadataGenre(MP4hFile, genre); if (comment) MP4SetMetadataComment(MP4hFile, comment); if (artSize) { MP4SetMetadataCoverArt(MP4hFile, art, artSize); free(art); } } else { #endif /* open the aac output file */ if (!strcmp(aacFileName, "-")) { outfile = stdout; } else { outfile = fopen(aacFileName, "wb"); } if (!outfile) { fprintf(stderr, "Couldn't create output file %s\n", aacFileName); return 1; } #ifdef HAVE_LIBMP4V2 } #endif cutOff = myFormat->bandWidth; quantqual = myFormat->quantqual; bitRate = myFormat->bitRate; if (bitRate) fprintf(stderr, "Average bitrate: %d kbps\n", (bitRate + 500)/1000*infile->channels); fprintf(stderr, "Quantization quality: %ld\n", quantqual); fprintf(stderr, "Bandwidth: %d Hz\n", cutOff); fprintf(stderr, "Object type: "); switch(objectType) { case LOW: fprintf(stderr, "Low Complexity"); break; case MAIN: fprintf(stderr, "Main"); break; case LTP: fprintf(stderr, "LTP"); break; } fprintf(stderr, "(MPEG-%d)", (mpegVersion == MPEG4) ? 4 : 2); if (myFormat->useTns) fprintf(stderr, " + TNS"); if (myFormat->allowMidside) fprintf(stderr, " + M/S"); fprintf(stderr, "\n"); fprintf(stderr, "Container format: "); switch(container) { case NO_CONTAINER: switch(stream) { case RAW_STREAM: fprintf(stderr, "Headerless AAC (RAW)\n"); break; case ADTS_STREAM: fprintf(stderr, "Transport Stream (ADTS)\n"); break; } break; #ifdef HAVE_LIBMP4V2 case MP4_CONTAINER: fprintf(stderr, "MPEG-4 File Format (MP4)\n"); break; #endif } if (outfile #ifdef HAVE_LIBMP4V2 || MP4hFile != MP4_INVALID_FILE_HANDLE #endif ) { int showcnt = 0; #ifdef _WIN32 long begin = GetTickCount(); #endif if (infile->samples) frames = ((infile->samples + 1023) / 1024) + 1; else frames = 0; currentFrame = 0; fprintf(stderr, "Encoding %s to %s\n", audioFileName, aacFileName); if (frames != 0) fprintf(stderr, " frame | bitrate | elapsed/estim | " "play/CPU | ETA\n"); else fprintf(stderr, " frame | elapsed | play/CPU\n"); /* encoding loop */ #ifdef _WIN32 for (;;) #else while (running) #endif { int bytesWritten; samplesRead = wav_read_float32(infile, pcmbuf, samplesInput, chanmap); #ifdef HAVE_LIBMP4V2 total_samples += samplesRead / infile->channels; #endif /* call the actual encoding routine */ bytesWritten = faacEncEncode(hEncoder, (int32_t *)pcmbuf, samplesRead, bitbuf, maxBytesOutput); if (bytesWritten) { currentFrame++; showcnt--; totalBytesWritten += bytesWritten; } if ((showcnt <= 0) || !bytesWritten) { double timeused; #ifdef __unix__ struct rusage usage; #endif #ifdef _WIN32 char percent[MAX_PATH + 20]; timeused = (GetTickCount() - begin) * 1e-3; #else #ifdef __unix__ if (getrusage(RUSAGE_SELF, &usage) == 0) { timeused = (double)usage.ru_utime.tv_sec + (double)usage.ru_utime.tv_usec * 1e-6; } else timeused = 0; #else timeused = (double)clock() * (1.0 / CLOCKS_PER_SEC); #endif #endif if (currentFrame && (timeused > 0.1)) { showcnt += 50; if (frames != 0) fprintf(stderr, "\r%5d/%-5d (%3d%%)| %5.1f | %6.1f/%-6.1f | %7.2fx | %.1f ", currentFrame, frames, currentFrame*100/frames, ((double)totalBytesWritten * 8.0 / 1000.0) / ((double)infile->samples / infile->samplerate * currentFrame / frames), timeused, timeused * frames / currentFrame, (1024.0 * currentFrame / infile->samplerate) / timeused, timeused * (frames - currentFrame) / currentFrame); else fprintf(stderr, "\r %5d | %6.1f | %7.2fx ", currentFrame, timeused, (1024.0 * currentFrame / infile->samplerate) / timeused); fflush(stderr); #ifdef _WIN32 if (frames != 0) { sprintf(percent, "%.2f%% encoding %s", 100.0 * currentFrame / frames, audioFileName); SetConsoleTitle(percent); } #endif } } /* all done, bail out */ if (!samplesRead && !bytesWritten) break ; if (bytesWritten < 0) { fprintf(stderr, "faacEncEncode() failed\n"); break ; } if (bytesWritten > 0) { #ifdef HAVE_LIBMP4V2 u_int64_t samples_left = total_samples - encoded_samples + delay_samples; MP4Duration dur = samples_left > frameSize ? frameSize : samples_left; MP4Duration ofs = encoded_samples > 0 ? 0 : delay_samples; if (container == MP4_CONTAINER) { /* write bitstream to mp4 file */ MP4WriteSample(MP4hFile, MP4track, bitbuf, bytesWritten, dur, ofs, 1); } else { #endif /* write bitstream to aac file */ fwrite(bitbuf, 1, bytesWritten, outfile); #ifdef HAVE_LIBMP4V2 } encoded_samples += dur; #endif } } #ifdef HAVE_LIBMP4V2 /* clean up */ if (container == MP4_CONTAINER) { MP4Close(MP4hFile); if (optimizeFlag == 1) { fprintf(stderr, "\n\nMP4 format optimization... "); MP4Optimize(aacFileName, NULL, 0); fprintf(stderr, "Done!"); } } else #endif fclose(outfile); fprintf(stderr, "\n\n"); } faacEncClose(hEncoder); wav_close(infile); if (pcmbuf) free(pcmbuf); if (bitbuf) free(bitbuf); if (aacFileNameGiven) free(aacFileName); } return 0; }
static DB_playItem_t * aac_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { trace ("adding %s\n", fname); DB_FILE *fp = deadbeef->fopen (fname); if (!fp) { trace ("not found\n"); return NULL; } aac_info_t info = {0}; info.junk = deadbeef->junk_get_leading_size (fp); if (info.junk >= 0) { trace ("junk: %d\n", info.junk); deadbeef->fseek (fp, info.junk, SEEK_SET); } else { info.junk = 0; } const char *ftype = NULL; float duration = -1; int totalsamples = 0; int samplerate = 0; int channels = 0; int mp4track = -1; MP4FILE mp4 = NULL; if (fp->vfs->is_streaming ()) { trace ("streaming aac (%s)\n", fname); ftype = "RAW AAC"; } else { // slowwww! info.file = fp; MP4FILE_CB cb = { #ifdef USE_MP4FF .read = aac_fs_read, .write = NULL, .seek = aac_fs_seek, .truncate = NULL, .user_data = &info #else .open = aac_fs_open, .seek = aac_fs_seek, .read = aac_fs_read, .write = NULL, .close = aac_fs_close #endif }; int res = aac_probe (fp, fname, &cb, &duration, &samplerate, &channels, &totalsamples, &mp4track, &mp4); if (res == -1) { deadbeef->fclose (fp); return NULL; } else if (res == 0) { ftype = "MP4 AAC"; } else if (res == 1) { ftype = "RAW AAC"; } } DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id); deadbeef->pl_add_meta (it, ":FILETYPE", ftype); deadbeef->plt_set_item_duration (plt, it, duration); trace ("duration: %f sec\n", duration); // read tags if (mp4) { #ifdef USE_MP4FF aac_load_tags (it, mp4); mp4ff_close (mp4); #else const MP4Tags *tags = MP4TagsAlloc (); MP4TagsFetch (tags, mp4); deadbeef->pl_add_meta (it, "title", tags->name); deadbeef->pl_add_meta (it, "artist", tags->artist); deadbeef->pl_add_meta (it, "albumArtist", tags->albumArtist); deadbeef->pl_add_meta (it, "album", tags->album); deadbeef->pl_add_meta (it, "composer", tags->composer); deadbeef->pl_add_meta (it, "comments", tags->comments); deadbeef->pl_add_meta (it, "genre", tags->genre); deadbeef->pl_add_meta (it, "year", tags->releaseDate); char s[10]; if (tags->track) { snprintf (s, sizeof (s), "%d", tags->track->index); deadbeef->pl_add_meta (it, "track", s); snprintf (s, sizeof (s), "%d", tags->track->total); deadbeef->pl_add_meta (it, "numtracks", s); } if (tags->disk) { snprintf (s, sizeof (s), "%d", tags->disk->index); deadbeef->pl_add_meta (it, "disc", s); snprintf (s, sizeof (s), "%d", tags->disk->total); deadbeef->pl_add_meta (it, "numdiscs", s); } deadbeef->pl_add_meta (it, "copyright", tags->copyright); deadbeef->pl_add_meta (it, "vendor", tags->encodedBy); deadbeef->pl_add_meta (it, "title", NULL); MP4TagsFree (tags); MP4Close (mp4); #endif } int apeerr = deadbeef->junk_apev2_read (it, fp); int v2err = deadbeef->junk_id3v2_read (it, fp); int v1err = deadbeef->junk_id3v1_read (it, fp); deadbeef->pl_add_meta (it, "title", NULL); int64_t fsize = deadbeef->fgetlength (fp); deadbeef->fclose (fp); if (duration > 0) { char s[100]; snprintf (s, sizeof (s), "%lld", fsize); deadbeef->pl_add_meta (it, ":FILE_SIZE", s); deadbeef->pl_add_meta (it, ":BPS", "16"); snprintf (s, sizeof (s), "%d", channels); deadbeef->pl_add_meta (it, ":CHANNELS", s); snprintf (s, sizeof (s), "%d", samplerate); deadbeef->pl_add_meta (it, ":SAMPLERATE", s); int br = (int)roundf(fsize / duration * 8 / 1000); snprintf (s, sizeof (s), "%d", br); deadbeef->pl_add_meta (it, ":BITRATE", s); // embedded cue deadbeef->pl_lock (); const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet"); DB_playItem_t *cue = NULL; if (cuesheet) { cue = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), totalsamples, samplerate); if (cue) { deadbeef->pl_item_unref (it); deadbeef->pl_item_unref (cue); deadbeef->pl_unlock (); return cue; } } deadbeef->pl_unlock (); cue = deadbeef->plt_insert_cue (plt, after, it, totalsamples, samplerate); if (cue) { deadbeef->pl_item_unref (it); deadbeef->pl_item_unref (cue); return cue; } } deadbeef->pl_add_meta (it, "title", NULL); after = deadbeef->plt_insert_item (plt, after, it); deadbeef->pl_item_unref (it); return after; } static const char * exts[] = { "aac", "mp4", "m4a", NULL }; // define plugin interface static DB_decoder_t plugin = { .plugin.api_vmajor = 1, .plugin.api_vminor = 0, .plugin.version_major = 1, .plugin.version_minor = 0, .plugin.type = DB_PLUGIN_DECODER, .plugin.id = "aac", .plugin.name = "AAC player", .plugin.descr = "plays aac files, supports raw aac files, as well as mp4 container", .plugin.copyright = "Copyright (C) 2009-2012 Alexey Yakovenko <*****@*****.**>\n" "\n" "Uses modified libmp4ff (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com\n" "\n" "This program is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU General Public License\n" "as published by the Free Software Foundation; either version 2\n" "of the License, or (at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program; if not, write to the Free Software\n" "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n" , .plugin.website = "http://deadbeef.sf.net", .open = aac_open, .init = aac_init, .free = aac_free, .read = aac_read, .seek = aac_seek, .seek_sample = aac_seek_sample, .insert = aac_insert, .read_metadata = aac_read_metadata, #ifdef USE_MP4FF // mp4ff metadata writer doesn't work // .write_metadata = aac_write_metadata, #else #endif .exts = exts, }; DB_plugin_t * aac_load (DB_functions_t *api) { deadbeef = api; return DB_PLUGIN (&plugin); }
// returns -1 for error, 0 for mp4, 1 for aac int aac_probe (DB_FILE *fp, const char *fname, MP4FILE_CB *cb, float *duration, int *samplerate, int *channels, int *totalsamples, int *mp4track, MP4FILE *pmp4) { // try mp4 trace ("aac_probe: pos=%lld, junk=%d\n", deadbeef->ftell (fp), ((aac_info_t*)cb->user_data)->junk); if (mp4track) { *mp4track = -1; } if (*pmp4) { *pmp4 = NULL; } *duration = -1; #ifdef USE_MP4FF trace ("mp4ff_open_read\n"); mp4ff_t *mp4 = mp4ff_open_read (cb); #else MP4FileHandle mp4 = MP4ReadProvider (fname, 0, cb); #endif if (!mp4) { trace ("not an mp4 file\n"); return -1; } if (pmp4) { *pmp4 = mp4; } #ifdef USE_MP4FF int ntracks = mp4ff_total_tracks (mp4); if (ntracks > 0) { trace ("m4a container detected, ntracks=%d\n", ntracks); int i = -1; trace ("looking for mp4 data...\n"); int sr = -1; unsigned char* buff = 0; unsigned int buff_size = 0; for (i = 0; i < ntracks; i++) { mp4AudioSpecificConfig mp4ASC; mp4ff_get_decoder_config(mp4, i, &buff, &buff_size); if (buff) { int rc = AudioSpecificConfig(buff, buff_size, &mp4ASC); sr = mp4ASC.samplingFrequency; if(rc < 0) { free (buff); buff = 0; continue; } break; } } if (i != ntracks && buff) { trace ("found audio track (%d)\n", i); // init mp4 decoding NeAACDecHandle dec = NeAACDecOpen (); unsigned long srate; unsigned char ch; if (NeAACDecInit2(dec, buff, buff_size, &srate, &ch) < 0) { trace ("NeAACDecInit2 returned error\n"); goto error; } *samplerate = srate; *channels = ch; int samples = mp4ff_num_samples(mp4, i); samples = (int64_t)samples * srate / mp4ff_time_scale (mp4, i); int tsamples = samples; NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (dec); conf->dontUpSampleImplicitSBR = 1; NeAACDecSetConfiguration (dec, conf); mp4AudioSpecificConfig mp4ASC; int mp4framesize; if (NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC) >= 0) { mp4framesize = 1024; if (mp4ASC.frameLengthFlag == 1) { mp4framesize = 960; } // commented this out, since it fixes double-duration bug on // some mp4 files //if (mp4ASC.sbr_present_flag == 1) { // mp4framesize *= 2; //} } else { trace ("NeAACDecAudioSpecificConfig failed, can't get mp4framesize\n"); goto error; } tsamples *= mp4framesize; trace ("mp4 nsamples=%d, samplerate=%d, timescale=%d, duration=%lld\n", samples, *samplerate, mp4ff_time_scale(mp4, i), mp4ff_get_track_duration(mp4, i)); *duration = (float)tsamples / (*samplerate); trace ("mp4 duration: %f (tsamples %d/samplerate %d)\n", *duration, tsamples, *samplerate); NeAACDecClose (dec); if (totalsamples) { *totalsamples = tsamples; } if (mp4track) { *mp4track = i; } if (!*pmp4) { mp4ff_close (mp4); } return 0; error: NeAACDecClose (dec); free (buff); if (!*pmp4) { mp4ff_close (mp4); } return -1; } else { trace ("audio track not found\n"); mp4ff_close (mp4); mp4 = NULL; } if (buff) { free (buff); buff = NULL; } } #else MP4FileHandle mp4File = mp4; MP4TrackId trackId = MP4FindTrackId(mp4File, 0, "audio", 0); trace ("trackid: %d\n", trackId); uint32_t timeScale = MP4GetTrackTimeScale(mp4File, trackId); MP4Duration trackDuration = MP4GetTrackDuration(mp4File, trackId); MP4SampleId numSamples = MP4GetTrackNumberOfSamples(mp4File, trackId); u_int8_t* pConfig; uint32_t configSize = 0; bool res = MP4GetTrackESConfiguration(mp4File, trackId, &pConfig, &configSize); if (res && pConfig) { mp4AudioSpecificConfig mp4ASC; int rc = AudioSpecificConfig(pConfig, configSize, &mp4ASC); free (pConfig); if (rc >= 0) { *samplerate = mp4ASC.samplingFrequency; *channels = MP4GetTrackAudioChannels (mp4File, trackId); // int64_t duration = MP4ConvertFromTrackDuration (mp4File, trackId, trackDuration, timeScale); int samples = MP4GetTrackNumberOfSamples (mp4File, trackId) * 1024 * (*channels); trace ("mp4 nsamples=%d, timescale=%d, samplerate=%d\n", samples, timeScale, *samplerate); *duration = (float)samples / (*samplerate); if (totalsamples) { *totalsamples = samples; } if (mp4track) { *mp4track = trackId; } if (!*pmp4) { MP4Close (mp4); } return 0; } } #endif if (*pmp4) { *pmp4 = NULL; } if (mp4) { #if USE_MP4FF mp4ff_close (mp4); #else MP4Close (mp4); #endif mp4 = NULL; } trace ("mp4 track not found, looking for aac stream...\n"); // not an mp4, try raw aac #if USE_MP4FF deadbeef->rewind (fp); #endif if (parse_aac_stream (fp, samplerate, channels, duration, totalsamples) == -1) { trace ("aac stream not found\n"); return -1; } trace ("found aac stream\n"); return 1; }
static int aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) { aac_info_t *info = (aac_info_t *)_info; info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI")); if (!info->file) { return -1; } // probe float duration = -1; int samplerate = -1; int channels = -1; int totalsamples = -1; info->junk = deadbeef->junk_get_leading_size (info->file); if (!info->file->vfs->is_streaming ()) { if (info->junk >= 0) { deadbeef->fseek (info->file, info->junk, SEEK_SET); } else { info->junk = 0; } } else { deadbeef->fset_track (info->file, it); } info->mp4track = -1; #if USE_MP4FF info->mp4reader.read = aac_fs_read; info->mp4reader.write = NULL; info->mp4reader.seek = aac_fs_seek; info->mp4reader.truncate = NULL; info->mp4reader.user_data = info; #else info->mp4reader.open = aac_fs_open; info->mp4reader.seek = aac_fs_seek; info->mp4reader.read = aac_fs_read; info->mp4reader.write = NULL; info->mp4reader.close = aac_fs_close; #endif if (!info->file->vfs->is_streaming ()) { #ifdef USE_MP4FF trace ("aac_init: mp4ff_open_read %s\n", deadbeef->pl_find_meta (it, ":URI")); info->mp4file = mp4ff_open_read (&info->mp4reader); if (info->mp4file) { int ntracks = mp4ff_total_tracks (info->mp4file); if (ntracks > 0) { trace ("m4a container detected, ntracks=%d\n", ntracks); int i = -1; unsigned char* buff = 0; unsigned int buff_size = 0; for (i = 0; i < ntracks; i++) { mp4AudioSpecificConfig mp4ASC; mp4ff_get_decoder_config (info->mp4file, i, &buff, &buff_size); if(buff){ int rc = AudioSpecificConfig(buff, buff_size, &mp4ASC); if(rc < 0) continue; break; } } trace ("mp4 probe-buffer size: %d\n", buff_size); if (i != ntracks && buff) { trace ("mp4 track: %d\n", i); int samples = mp4ff_num_samples(info->mp4file, i); info->mp4samples = samples; info->mp4track = i; // init mp4 decoding info->dec = NeAACDecOpen (); unsigned long srate; unsigned char ch; if (NeAACDecInit2(info->dec, buff, buff_size, &srate, &ch) < 0) { trace ("NeAACDecInit2 returned error\n"); free (buff); return -1; } samplerate = srate; channels = ch; samples = (int64_t)samples * srate / mp4ff_time_scale (info->mp4file, i); totalsamples = samples; NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec); conf->dontUpSampleImplicitSBR = 1; NeAACDecSetConfiguration (info->dec, conf); mp4AudioSpecificConfig mp4ASC; if (NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC) >= 0) { info->mp4framesize = 1024; if (mp4ASC.frameLengthFlag == 1) { info->mp4framesize = 960; } // if (mp4ASC.sbr_present_flag == 1) { // info->mp4framesize *= 2; // } } totalsamples *= info->mp4framesize; duration = (float)totalsamples / samplerate; } else { mp4ff_close (info->mp4file); info->mp4file = NULL; } if (buff) { free (buff); } } else { mp4ff_close (info->mp4file); info->mp4file = NULL; } } // {{{ libmp4v2 code #else trace ("aac_init: MP4ReadProvider %s\n", deadbeef->pl_find_meta (it, ":URI")); info->mp4file = MP4ReadProvider (deadbeef->pl_find_meta (it, ":URI"), 0, &info->mp4reader); info->mp4track = MP4FindTrackId(info->mp4file, 0, "audio", 0); trace ("aac_init: MP4FindTrackId returned %d\n", info->mp4track); if (info->mp4track >= 0) { info->timescale = MP4GetTrackTimeScale(info->mp4file, info->mp4track); u_int8_t* pConfig; uint32_t configSize = 0; bool res = MP4GetTrackESConfiguration(info->mp4file, info->mp4track, &pConfig, &configSize); mp4AudioSpecificConfig mp4ASC; int rc = AudioSpecificConfig(pConfig, configSize, &mp4ASC); if (rc >= 0) { _info->samplerate = mp4ASC.samplingFrequency; _info->channels = MP4GetTrackAudioChannels (info->mp4file, info->mp4track); totalsamples = MP4GetTrackNumberOfSamples (info->mp4file, info->mp4track) * 1024 * _info->channels; // init mp4 decoding info->dec = NeAACDecOpen (); unsigned long srate; unsigned char ch; if (NeAACDecInit2(info->dec, pConfig, configSize, &srate, &ch) < 0) { trace ("NeAACDecInit2 returned error\n"); return -1; } samplerate = srate; channels = ch; NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec); conf->dontUpSampleImplicitSBR = 1; NeAACDecSetConfiguration (info->dec, conf); mp4AudioSpecificConfig mp4ASC; if (NeAACDecAudioSpecificConfig(pConfig, configSize, &mp4ASC) >= 0) { info->mp4framesize = 1024; if (mp4ASC.frameLengthFlag == 1) { info->mp4framesize = 960; } // if (mp4ASC.sbr_present_flag == 1) { // info->mp4framesize *= 2; // } } //totalsamples *= info->mp4framesize; free (pConfig); info->maxSampleSize = MP4GetTrackMaxSampleSize(info->mp4file, info->mp4track); info->samplebuffer = malloc (info->maxSampleSize); info->mp4sample = 1; } else { MP4Close (info->mp4file); info->mp4file = NULL; } } else { MP4Close (info->mp4file); info->mp4file = NULL; } #endif // }}} if (!info->mp4file) { trace ("mp4 track not found, looking for aac stream...\n"); if (info->junk >= 0) { deadbeef->fseek (info->file, info->junk, SEEK_SET); } else { deadbeef->rewind (info->file); } int offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, &totalsamples); if (offs == -1) { trace ("aac stream not found\n"); return -1; } if (offs > info->junk) { info->junk = offs; } if (info->junk >= 0) { deadbeef->fseek (info->file, info->junk, SEEK_SET); } else { deadbeef->rewind (info->file); } trace ("found aac stream (junk: %d, offs: %d)\n", info->junk, offs); } _info->fmt.channels = channels; _info->fmt.samplerate = samplerate; } else { // sync before attempting to init int samplerate, channels; float duration; int offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, NULL); if (offs < 0) { trace ("aac: parse_aac_stream failed\n"); return -1; } if (offs > info->junk) { info->junk = offs; } trace("parse_aac_stream returned %x\n", offs); deadbeef->pl_replace_meta (it, "!FILETYPE", "AAC"); } // duration = (float)totalsamples / samplerate; // deadbeef->pl_set_item_duration (it, duration); _info->fmt.bps = 16; _info->plugin = &plugin; if (!info->mp4file) { //trace ("NeAACDecGetCapabilities\n"); //unsigned long caps = NeAACDecGetCapabilities(); trace ("NeAACDecOpen\n"); info->dec = NeAACDecOpen (); trace ("prepare for NeAACDecInit: fread %d from offs %lld\n", AAC_BUFFER_SIZE, deadbeef->ftell (info->file)); info->remaining = deadbeef->fread (info->buffer, 1, AAC_BUFFER_SIZE, info->file); NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec); // conf->dontUpSampleImplicitSBR = 1; NeAACDecSetConfiguration (info->dec, conf); unsigned long srate; unsigned char ch; trace ("NeAACDecInit (%d bytes)\n", info->remaining); int consumed = NeAACDecInit (info->dec, info->buffer, info->remaining, &srate, &ch); trace ("NeAACDecInit returned samplerate=%d, channels=%d, consumed: %d\n", (int)srate, (int)ch, consumed); if (consumed < 0) { trace ("NeAACDecInit returned %d\n", consumed); return -1; } if (consumed > info->remaining) { trace ("NeAACDecInit consumed more than available! wtf?\n"); return -1; } if (consumed == info->remaining) { info->remaining = 0; } else if (consumed > 0) { memmove (info->buffer, info->buffer + consumed, info->remaining - consumed); info->remaining -= consumed; } _info->fmt.channels = ch; _info->fmt.samplerate = srate; } if (!info->file->vfs->is_streaming ()) { if (it->endsample > 0) { info->startsample = it->startsample; info->endsample = it->endsample; plugin.seek_sample (_info, 0); } else { info->startsample = 0; info->endsample = totalsamples-1; } } trace ("totalsamples: %d, endsample: %d, samples-from-duration: %d\n", totalsamples-1, info->endsample, (int)deadbeef->pl_get_item_duration (it)*44100); for (int i = 0; i < _info->fmt.channels; i++) { _info->fmt.channelmask |= 1 << i; } info->noremap = 0; info->remap[0] = -1; trace ("init success\n"); return 0; }
int decodeMP4file(char *sndfile, aac_dec_opt *opt) { int track; unsigned long samplerate; unsigned char channels; void *sample_buffer; MP4FileHandle infile; MP4SampleId sampleId, numSamples; audio_file *aufile; faacDecHandle hDecoder; faacDecFrameInfo frameInfo; unsigned char *buffer; int buffer_size; int first_time = 1; hDecoder = faacDecOpen(); infile = MP4Read(opt->filename, 0); if (!infile) { /* unable to open file */ error_handler("Error opening file: %s\n", opt->filename); return 1; } if ((track = GetAACTrack(infile)) < 0) { error_handler("Unable to find correct AAC sound track in the MP4 file.\n"); MP4Close(infile); return 1; } buffer = NULL; buffer_size = 0; MP4GetTrackESConfiguration(infile, track, &buffer, &buffer_size); if(faacDecInit2(hDecoder, buffer, buffer_size, &samplerate, &channels) < 0) { /* If some error initializing occured, skip the file */ error_handler("Error initializing decoder library.\n"); faacDecClose(hDecoder); MP4Close(infile); return 1; } if (buffer) free(buffer); numSamples = MP4GetTrackNumberOfSamples(infile, track); for (sampleId = 1; sampleId <= numSamples; sampleId++) { int rc; /* get access unit from MP4 file */ buffer = NULL; buffer_size = 0; rc = MP4ReadSample(infile, track, sampleId, &buffer, &buffer_size, NULL, NULL, NULL, NULL); if (rc == 0) { error_handler("Reading from MP4 file failed.\n"); faacDecClose(hDecoder); MP4Close(infile); return 1; } sample_buffer = faacDecDecode(hDecoder, &frameInfo, buffer, buffer_size); if (buffer) free(buffer); opt->progress_update((long)numSamples, sampleId); /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { if(opt->decode_mode == 0) { if (Set_WIN_Params (INVALID_FILEDESC, samplerate, SAMPLE_SIZE, frameInfo.channels) < 0) { error_handler("\nCan't access %s\n", "WAVE OUT"); faacDecClose(hDecoder); MP4Close(infile); return (0); } } else { aufile = open_audio_file(sndfile, samplerate, frameInfo.channels, opt->output_format, opt->file_type, aacChannelConfig2wavexChannelMask(&frameInfo)); if (aufile == NULL) { faacDecClose(hDecoder); MP4Close(infile); return 0; } } first_time = 0; } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { if(opt->decode_mode == 0) WIN_Play_Samples((short*)sample_buffer, frameInfo.channels*frameInfo.samples); else write_audio_file(aufile, sample_buffer, frameInfo.samples, 0); } if (frameInfo.error > 0) { error_handler("Error: %s\n", faacDecGetErrorMessage(frameInfo.error)); break; } if(stop_decoding) break; } faacDecClose(hDecoder); MP4Close(infile); if(opt->decode_mode == 0) WIN_Audio_close(); else { if (!first_time) close_audio_file(aufile); } return frameInfo.error; }
bool mediaM4A(Artwork *art, const char *filePath) { MP4FileHandle mp4file = MP4Read(filePath); if (mp4file == MP4_INVALID_FILE_HANDLE) { return false; } uint16_t numvalue, numvalue2; char *value; u_int8_t numbool; art->filetype = FILETYPE_M4A; if (MP4GetMetadataArtist(mp4file, &value) && value != NULL) { art->artist = (QString::fromUtf8(value)).trimmed(); free(value); } if (MP4GetMetadataYear(mp4file, &value) && value != NULL) { art->year = QString(value).toInt(); free(value); } if (MP4GetMetadataAlbum(mp4file, &value) && value != NULL) { art->album = (QString::fromUtf8(value)).trimmed(); free(value); } if (MP4GetMetadataName(mp4file, &value) && value != NULL) { art->track = (QString::fromUtf8(value)).trimmed(); free(value); } if (MP4GetMetadataWriter(mp4file, &value) && value != NULL) { // composer free(value); } if (MP4GetMetadataTrack(mp4file, &numvalue, &numvalue2)) { art->trackNo = numvalue; art->trackCount = numvalue2; } if (MP4GetMetadataDisk(mp4file, &numvalue, &numvalue2)) { art->discNo = numvalue; art->discCount = numvalue2; } if (MP4GetMetadataGenre(mp4file, &value) && value != NULL) { art->genre = (QString::fromUtf8(value)).trimmed(); free(value); } if (MP4GetMetadataCompilation(mp4file, &numbool)) { art->type = numbool ? ARTWORK_COMPILATION : ARTWORK_NORMAL; } /* art->bitrate = 0; art->sampleRate = 0; art->channels = 0; */ MP4Duration duration = MP4GetDuration(mp4file); if (duration != MP4_INVALID_DURATION) { u_int64_t timescale = MP4GetTimeScale(mp4file); u_int64_t msectime = (duration * (u_int64_t) 1000) / timescale; u_int64_t sectime, mintime, hrtime; if (msectime == 0) { hrtime = mintime = sectime = (u_int64_t) 0; } else { hrtime = msectime / (u_int64_t) (3600 * 1000); msectime -= hrtime * (u_int64_t) (3600 * 1000); mintime = msectime / (u_int64_t) (60 * 1000); msectime -= (mintime * (u_int64_t) (60 * 1000)); sectime = msectime / (u_int64_t) (1000); msectime -= sectime * (u_int64_t)(1000); } art->duration = hrtime * 3600 + mintime * 60 + sectime; } art->makeSearchable(); if (!art->hasCover()) { uint8_t *cover = NULL; uint32_t cover_size; if (MP4GetMetadataCoverArt(mp4file, &cover, &cover_size)) { if (saveImage(art, (const char*) cover, cover_size)) { qDebug() << "MP4: invalid image in " << filePath; } } if (cover) { free(cover); } } MP4Close(mp4file); return true; }