ref: e4b87483df3b5a4cb2a42d69fbfea649908aa71b
parent: 01584c198c3052681db9309914afd92543182ff8
author: menno <menno>
date: Tue Sep 2 16:12:18 EDT 2003
New xmms MP4 plugin from ciber-fred
--- /dev/null
+++ b/plugins/xmmsmp4/src/Makefile.am
@@ -1,0 +1,10 @@
+libdir = `xmms-config --input-plugin-dir`
+
+lib_LTLIBRARIES = libmp4.la
+libmp4_la_CFLAGS = -I../mp4v2 -I../libmp4v2-include -I../libfaad-include `xmms-config --cflags` -DHAVE_GLIB_H=1
+
+libmp4_la_LDFLAGS = -module -avoid-version `xmms-config --libs` -lpthread -lstdc++
+
+libmp4_la_LIBADD = $(top_builddir)/libfaad/libfaad.la $(top_builddir)/mp4v2/libmp4v2.la
+
+libmp4_la_SOURCES = libmp4.c libmp4_utils.c libmp4_utils.h
--- /dev/null
+++ b/plugins/xmmsmp4/src/libmp4.c
@@ -1,0 +1,303 @@
+/*
+** a mp4 AAC audio player for XMMS by ciberfred
+**
+*/
+
+#include "mp4.h"
+#include <pthread.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+
+#include "faad.h"
+
+#include "xmms/plugin.h"
+#include "xmms/util.h"
+#include "xmms/configfile.h"
+#include "xmms/titlestring.h"
+
+#include "libmp4_utils.h"
+
+#define MP4_DESCRIPTION "MP4 audio player - 1.2.7"
+#define MP4_VERSION "mp4 audio player (v0.3) - 1 Aout 2003"
+#define MP4_ABOUT "Written from scratch by ciberfred"
+
+static void mp4_init(void);
+static void mp4_about(void);
+static void mp4_play(char *);
+static void mp4_stop(void);
+static void mp4_pause(short);
+static void mp4_seek(int);
+static int mp4_getTime(void);
+static void mp4_cleanup(void);
+static void mp4_getSongInfo(char *);
+static int mp4_isFile(char *);
+
+static void *mp4Decode(void *args);
+
+InputPlugin mp4_ip =
+ {
+ 0, // handle
+ 0, // filename
+ MP4_DESCRIPTION,
+ mp4_init,
+ mp4_about,
+ 0, // configuration
+ mp4_isFile,
+ 0, //scandir
+ mp4_play,
+ mp4_stop,
+ mp4_pause,
+ mp4_seek,
+ 0, // set equalizer
+ mp4_getTime,
+ 0, // get volume
+ 0,
+ mp4_cleanup,
+ 0, // obsolete
+ 0, // send visualisation data
+ 0, // set player window info
+ 0, // set song title text
+ 0, // get song title text
+ mp4_getSongInfo, // info box
+ 0, // to output plugin
+ };
+
+
+static gboolean bPlaying = FALSE;
+static pthread_t decodeThread;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static int seekPosition = -1;
+
+InputPlugin *get_iplugin_info(void)
+{
+ return(&mp4_ip);
+}
+
+static void mp4_init(void)
+{
+ memset(&decodeThread, 0, sizeof(pthread_t));
+ return;
+}
+
+static void mp4_play(char *filename)
+{
+ bPlaying = TRUE;
+ pthread_create(&decodeThread, 0, mp4Decode, g_strdup(filename));
+ return;
+}
+
+static void mp4_stop(void)
+{
+ if(bPlaying){
+ bPlaying = FALSE;
+ pthread_join(decodeThread, NULL);
+ memset(&decodeThread, 0, sizeof(pthread_t));
+ mp4_ip.output->close_audio();
+ }
+}
+
+static void *mp4Decode(void *args)
+{
+ unsigned long msDuration;
+ unsigned char *buffer = NULL;
+ int bufferSize = 0;
+ int lastframe = 0;
+ faacDecHandle decoder;
+ MP4SampleId numSamples;
+ MP4SampleId sampleID=1;
+ MP4FileHandle mp4file;
+ MP4Duration duration;
+ int mp4track;
+ unsigned long samplerate;
+ unsigned char channels;
+ unsigned int avgBitrate;
+
+
+ pthread_mutex_lock(&mutex);
+ seekPosition = -1;
+ bPlaying = TRUE;
+ if(!(mp4file = MP4Read(args, 0))){
+ printf("can't open file: %s\n", args);
+ free(args);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ if((mp4track = getAACTrack(mp4file)) < 0){
+// check here for others Audio format.....
+
+ g_print("Unsupported Audio track type\n");
+ free(args);
+ MP4Close(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ decoder = faacDecOpen();
+ MP4GetTrackESConfiguration(mp4file, mp4track, &buffer, &bufferSize);
+ if(!buffer){
+ free(args);
+ faacDecClose(decoder);
+ MP4Close(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ if(faacDecInit2(decoder, buffer, bufferSize, &samplerate, &channels)<0){
+ free(args);
+ faacDecClose(decoder);
+ MP4Close(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ free(buffer);
+ if(channels == 0){
+ g_print("Number of Channels not supported\n");
+ free(args);
+ faacDecClose(decoder);
+ MP4Close(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ mp4_ip.output->open_audio(FMT_S16_NE, samplerate, channels);
+ mp4_ip.output->flush(0);
+ g_print("MP4 flush\n");
+ duration = MP4GetTrackDuration(mp4file, mp4track);
+ msDuration = MP4ConvertFromTrackDuration(mp4file, mp4track, duration,
+ MP4_MSECS_TIME_SCALE);
+ numSamples = MP4GetTrackNumberOfSamples(mp4file, mp4track);
+ //mp4_ip.set_info(args, msDuration, -1, samplerate/1000, channels);
+
+ while(bPlaying){
+ void *sampleBuffer;
+ faacDecFrameInfo frameInfo;
+ int rc;
+
+ if(seekPosition!=-1){
+ duration = MP4ConvertToTrackDuration(mp4file, mp4track,seekPosition*1000,
+ MP4_MSECS_TIME_SCALE);
+ sampleID = MP4GetSampleIdFromTime(mp4file, mp4track, duration, 0);
+ mp4_ip.output->flush(seekPosition*1000);
+ seekPosition = -1;
+ }
+ buffer=NULL;
+ bufferSize=0;
+ if(sampleID > numSamples){
+ mp4_ip.output->close_audio();
+ free(args);
+ faacDecClose(decoder);
+ MP4Close(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ rc = MP4ReadSample(mp4file, mp4track, sampleID++, &buffer, &bufferSize,
+ NULL, NULL, NULL, NULL);
+ //g_print("%d/%d\n", sampleID-1, numSamples);
+ if((rc==0) || (buffer== NULL)){
+ printf("read error\n");
+ sampleBuffer = NULL;
+ sampleID=0;
+ mp4_ip.output->buffer_free();
+ mp4_ip.output->close_audio();
+ free(args);
+ faacDecClose(decoder);
+ MP4Close(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ else{
+ sampleBuffer = faacDecDecode(decoder, &frameInfo, buffer, bufferSize);
+ if(frameInfo.error > 0){
+ printf("FAAD2 error : %s\n", faacDecGetErrorMessage(frameInfo.error));
+ mp4_ip.output->close_audio();
+ free(args);
+ faacDecClose(decoder);
+ MP4Close(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ if(buffer){
+ free(buffer); buffer=0;
+ }
+ while(bPlaying && mp4_ip.output->buffer_free()<frameInfo.samples<<1)
+ xmms_usleep(30000);
+ }
+ //mp4_ip.add_vis_pcm(mp4_ip.output->written_time(), FMT_S16_NE, channels, frameInfo.samples<<1, sampleBuffer);
+ mp4_ip.output->write_audio(sampleBuffer, frameInfo.samples<<1);
+ }
+ while(bPlaying && mp4_ip.output->buffer_free()){
+ xmms_usleep(10000);
+ }
+ mp4_ip.output->close_audio();
+ free(args);
+ faacDecClose(decoder);
+ MP4Close(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+}
+
+static int mp4_isFile(char *filename)
+{
+ char *extention = strrchr(filename, '.');
+ if (extention &&
+ !strcasecmp(extention, ".mp4") ||
+ !strcasecmp(extention, ".m4a")
+ ){
+ return (1);
+ }
+ return(0);
+}
+
+static void mp4_about(void)
+{
+ static GtkWidget *aboutbox;
+
+ if(aboutbox!=NULL)
+ return;
+
+ aboutbox = xmms_show_message(
+ "About MP4 AAC player plugin",
+ "decoding engine : FAAD2 (30 July 2003)\n"
+ "plugin version : 0.3 (ciberfred)/static",
+ "Ok", FALSE, NULL, NULL);
+ gtk_signal_connect(GTK_OBJECT(aboutbox), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &aboutbox);
+}
+
+static void mp4_pause(short flag)
+{
+ mp4_ip.output->pause(flag);
+}
+
+static void mp4_seek(int time)
+{
+ seekPosition = time;
+ while(bPlaying && seekPosition!=-1) xmms_usleep(10000);
+}
+
+static int mp4_getTime(void)
+{
+ if (!bPlaying){
+ return (-1);
+ }
+ else{
+ return (mp4_ip.output->output_time());
+ }
+}
+
+static void mp4_cleanup(void)
+{
+}
+
+static void mp4_getSongInfo(char *filename)
+{
+ getMP4info(filename);
+}
--- /dev/null
+++ b/plugins/xmmsmp4/src/libmp4_utils.c
@@ -1,0 +1,153 @@
+/*
+** some function for MP4 file based on libmp4v2 from mpeg4ip project
+*/
+#include <mp4.h>
+#include <faad.h>
+#include "libmp4_utils.h"
+
+
+const char *mp4AudioNames[]=
+ {
+ "MPEG-1 Audio Layers 1,2 or 3",
+ "MPEG-2 low biterate (MPEG-1 extension) - MP3",
+ "MPEG-2 AAC Main Profile",
+ "MPEG-2 AAC Low Complexity profile",
+ "MPEG-2 AAC SSR profile",
+ "MPEG-4 audio (MPEG-4 AAC)",
+ 0
+ };
+
+const u_int8_t mp4AudioTypes[] =
+ {
+ MP4_MPEG1_AUDIO_TYPE, // 0x6B
+ MP4_MPEG2_AUDIO_TYPE, // 0x69
+ MP4_MPEG2_AAC_MAIN_AUDIO_TYPE, // 0x66
+ MP4_MPEG2_AAC_LC_AUDIO_TYPE, // 0x67
+ MP4_MPEG2_AAC_SSR_AUDIO_TYPE, // 0x68
+ MP4_MPEG4_AUDIO_TYPE, // 0x40
+ 0
+ };
+
+/* MPEG-4 Audio types from 14496-3 Table 1.5.1 (from mp4.h)*/
+const char *mpeg4AudioNames[]=
+ {
+ "!!!!MPEG-4 Audio track Invalid !!!!!!!",
+ "MPEG-4 AAC Main profile",
+ "MPEG-4 AAC Low Complexity profile",
+ "MPEG-4 AAC SSR profile",
+ "MPEG-4 AAC Long Term Prediction profile",
+ "MPEG-4 AAC Scalable",
+ "MPEG-4 CELP",
+ "MPEG-4 HVXC",
+ "MPEG-4 Text To Speech",
+ "MPEG-4 Main Synthetic profile",
+ "MPEG-4 Wavetable Synthesis profile",
+ "MPEG-4 MIDI Profile",
+ "MPEG-4 Algorithmic Synthesis and Audio FX profile"
+ };
+
+int getAACTrack(MP4FileHandle file)
+{
+ int numTracks = MP4GetNumberOfTracks(file, NULL, 0);
+ int i=0;
+
+ for(i=0;i<numTracks;i++){
+ MP4TrackId trackID = MP4FindTrackId(file, i, NULL, 0);
+ const char *trackType = MP4GetTrackType(file, trackID);
+ if(!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)){//we found audio track !
+ int j=0;
+ u_int8_t audiotype = MP4GetTrackAudioType(file, trackID);
+ while(mp4AudioTypes[j]){ // what kind of audio is ?
+ if(mp4AudioTypes[j] == audiotype){
+ if(mp4AudioTypes[j] == MP4_MPEG4_AUDIO_TYPE){//MPEG4 audio ok
+ audiotype = MP4GetTrackAudioMpeg4Type(file, trackID);
+ printf("%d-%s\n", audiotype, mpeg4AudioNames[audiotype]);
+ return (trackID);
+ }
+ else{
+ printf("%s\n", mp4AudioNames[j]);
+ if (mp4AudioTypes[j]== MP4_MPEG2_AAC_LC_AUDIO_TYPE ||
+ mp4AudioTypes[j]== MP4_MPEG2_AAC_MAIN_AUDIO_TYPE ||
+ mp4AudioTypes[j]== MP4_MPEG2_AAC_SSR_AUDIO_TYPE)
+ return(trackID);
+ return(-1);
+ }
+ }
+ j++;
+ }
+ }
+ }
+ return(-1);
+}
+
+int getAudioTrack(MP4FileHandle file)
+{
+ int numTracks = MP4GetNumberOfTracks(file, NULL,0);
+ int i=0;
+
+ for(i=0;i<numTracks;i++){
+ MP4TrackId trackID = MP4FindTrackId(file, i, NULL, 0);
+ const char *trackType = MP4GetTrackType(file, trackID);
+ if(!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)){
+ return(trackID);
+ }
+ }
+ return(-1);
+}
+
+int getVideoTrack(MP4FileHandle file)
+{
+ int numTracks = MP4GetNumberOfTracks(file, NULL, 0);
+ int i=0;
+
+ for(i=0;i<numTracks; i++){
+ MP4TrackId trackID = MP4FindTrackId(file, i, NULL, 0);
+ const char *trackType = MP4GetTrackType(file, trackID);
+ if(!strcmp(trackType, MP4_VIDEO_TRACK_TYPE)){
+ return (trackID);
+ }
+ }
+ return(-1);
+}
+
+void getMP4info(char* file)
+{
+ MP4FileHandle mp4file;
+ MP4Duration trackDuration;
+ int numTracks;
+ int i=0;
+
+ if(!(mp4file = MP4Read(file,0)))
+ return;
+ //MP4Dump(mp4file, 0, 0);
+ numTracks = MP4GetNumberOfTracks(mp4file, NULL, 0);
+ printf("there is %d track(s)\n", numTracks);
+ for(i=0;i<numTracks;i++){
+ MP4TrackId trackID = MP4FindTrackId(mp4file, i, NULL, 0);
+ const char *trackType = MP4GetTrackType(mp4file, trackID);
+ printf("Track %d, %s", trackID, trackType);
+ if(!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)){//we found audio track !
+ int j=0;
+ u_int8_t audiotype = MP4GetTrackAudioType(mp4file, trackID);
+ while(mp4AudioTypes[j]){ // what kind of audio is ?
+ if(mp4AudioTypes[j] == audiotype){
+ if(mp4AudioTypes[j] == MP4_MPEG4_AUDIO_TYPE){
+ audiotype = MP4GetTrackAudioMpeg4Type(mp4file, trackID);
+ printf(" %s", mpeg4AudioNames[audiotype]);
+ }
+ else{
+ printf(" %s", mp4AudioNames[j]);
+ }
+ printf(" duration :%d",
+ MP4ConvertFromTrackDuration(mp4file, trackID,
+ MP4GetTrackDuration(mp4file,
+ trackID),
+ MP4_MSECS_TIME_SCALE));
+ }
+ j++;
+ }
+ }
+ printf("\n");
+ }
+ MP4Close(mp4file);
+}
--- /dev/null
+++ b/plugins/xmmsmp4/src/libmp4_utils.h
@@ -1,0 +1,9 @@
+#ifndef __MP4UTILS_H_
+#define __MP4UTILS_H_
+
+int getAACTrack(MP4FileHandle);
+int getAudioTrack(MP4FileHandle);
+int getVideoTrack(MP4FileHandle);
+void getMP4info(char*);
+
+#endif