[Player-cvs] music/librarykit mmp_library.cpp, 1.3, 1.4 mmp_library_playqueue.cpp, 1.1.1.1, 1.2
bnewman at helixcommunity.org bnewman at helixcommunity.orgUpdate of /cvsroot/player/music/librarykit
In directory cvs-new:/tmp/cvs-serv9431
Modified Files:
mmp_library.cpp mmp_library_playqueue.cpp
Log Message:
Fixed play queue bug (Track 3 of 1 problem)
Added code to parse m4a file tags.
CRd by crobinson.
Index: mmp_library_playqueue.cpp
===================================================================
RCS file: /cvsroot/player/music/librarykit/mmp_library_playqueue.cpp,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -d -r1.1.1.1 -r1.2
--- mmp_library_playqueue.cpp 1 Jun 2004 23:47:05 -0000 1.1.1.1
+++ mmp_library_playqueue.cpp 19 Jul 2004 22:35:02 -0000 1.2
@@ -73,32 +73,37 @@
{
m_Queue.AddTail(pTrack);
- if (m_CurrentTrack == NULL)
- {
- m_CurrentTrack = m_Queue.GetTailPosition();
- }
+ m_CurrentTrack = m_Queue.GetTailPosition();
}
void
CMmpLibraryPlayQueue::GetNextTrack(CMmpTrack*& pTrack)
-{
- if (!m_Queue.IsEmpty() && m_CurrentTrack)
- {
- pTrack = (CMmpTrack*)m_Queue.GetNext(m_CurrentTrack);
-
- if (!m_CurrentTrack && m_bLoop)
- {
- m_CurrentTrackNum = 0;
- m_CurrentTrack = m_Queue.GetHeadPosition();
- pTrack = (CMmpTrack*)m_Queue.GetNext(m_CurrentTrack);
- }
-
- ++m_CurrentTrackNum;
- }
- else
- {
- pTrack = NULL;
- }
+{
+ if (!m_Queue.IsEmpty() && m_CurrentTrack)
+ {
+ pTrack = (CMmpTrack*)m_Queue.GetAtNext(m_CurrentTrack);
+
+ if (!m_CurrentTrack && m_bLoop)
+ {
+ m_CurrentTrackNum = 1;
+ m_CurrentTrack = m_Queue.GetHeadPosition();
+ pTrack = (CMmpTrack*)m_Queue.GetAt(m_CurrentTrack);
+ }
+ else if (!m_CurrentTrack)
+ {
+ m_CurrentTrackNum = m_Queue.GetCount();
+ m_CurrentTrack = m_Queue.GetTailPosition();
+ pTrack = (CMmpTrack*)m_Queue.GetAt(m_CurrentTrack);
+ }
+ else
+ {
+ ++m_CurrentTrackNum;
+ }
+ }
+ else
+ {
+ pTrack = NULL;
+ }
}
void
@@ -112,10 +117,18 @@
{
m_CurrentTrackNum = m_Queue.GetCount();
m_CurrentTrack = m_Queue.GetTailPosition();
- pTrack = (CMmpTrack*)m_Queue.GetNext(m_CurrentTrack);
+ pTrack = (CMmpTrack*)m_Queue.GetAt(m_CurrentTrack);
+ }
+ else if (!m_CurrentTrack)
+ {
+ m_CurrentTrackNum = 1;
+ m_CurrentTrack = m_Queue.GetHeadPosition();
+ pTrack = (CMmpTrack*)m_Queue.GetAt(m_CurrentTrack);
+ }
+ else
+ {
+ --m_CurrentTrackNum;
}
-
- --m_CurrentTrackNum;
}
else
{
Index: mmp_library.cpp
===================================================================
RCS file: /cvsroot/player/music/librarykit/mmp_library.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- mmp_library.cpp 9 Jul 2004 00:08:37 -0000 1.3
+++ mmp_library.cpp 19 Jul 2004 22:35:02 -0000 1.4
@@ -36,9 +36,12 @@
#include "mmp_library.h"
#include "mmp_library_track.h"
#include "mmp_library_id3v1.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
//
-// Metadata defines
+// RJMD Metadata defines
//
#define MD_RIFF_FOURCC HX_FOURCC('R','M','M','D')
@@ -49,7 +52,27 @@
#define RMMD_BIN_VERSION sizeof(UINT32)
#define RMMD_BIN_MDSIZE RMMD_BIN_VERSION+sizeof(UINT32)
#define RMMD_BIN_STATIC_SIZE sizeof(UINT32)*3
-
+
+//
+// M4A Tag Defines
+//
+
+#define GETUINT32(pbByte) ( (pbByte[0] << 24) + ((pbByte[1]& 0xff) << 16) + ((pbByte[2]& 0xff) << 8) + (pbByte[3] & 0xff) )
+#define SIZE_DATASIZE 4
+#define ATOM_IDSIZE 4
+#define SIZE_MODIFIER 4
+#define SIZE_DATATYPE 4
+#define MP4_BUILD_ATOMID(a,b,c,d) ( ((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+const char* kudta = "udta";
+const char* kmeta = "meta";
+const char* kilst = "ilst";
+const char* kVersionedAtomNames[] =
+{
+ "meta"
+ ,"mvhd"
+ ,""
+};
CMmpLibrary::CMmpLibrary()
{
@@ -386,7 +409,186 @@
exit:
return res;
}
-
+
+BOOL
+CMmpLibrary::IsVersionedM4aAtom(const char* szAtomName)
+{
+ const char** pszName = kVersionedAtomNames;
+
+ while(strlen(*pszName))
+ {
+ if(!stricmp(szAtomName, *pszName))
+ return TRUE;
+
+ pszName++;
+ }
+
+ return FALSE;
+}
+
+BOOL
+CMmpLibrary::FillM4aNamedAtomSturcture(const char *szName,
+ UINT32 nParentAtomOffset,
+ BOOL bParentAtomVersioned,
+ M4aAtomSizeAndOffset &atomStruct,
+ BYTE* pByteData,
+ UINT32 uDataSize)
+{
+ BOOL bFound = FALSE;
+ UINT32 nStartAtOffset = nParentAtomOffset + ATOM_IDSIZE + SIZE_DATASIZE;
+ if(bParentAtomVersioned)
+ {
+ nStartAtOffset += SIZE_DATASIZE;
+ }
+ BYTE* pbByte = pByteData + nStartAtOffset;
+ BYTE* pbEnd = pByteData + uDataSize;
+
+ if(!pbByte)
+ return bFound;
+
+
+ UINT32 uAtomSize = 0;
+ BOOL bVersionedAtom = FALSE;
+ while( !bFound && (pbByte < pbEnd) )
+ {
+ uAtomSize = 0;
+ bVersionedAtom = FALSE;
+
+ char szAtomName[ATOM_IDSIZE + 1];
+ memset(szAtomName, 0, sizeof(szAtomName));
+ uAtomSize = GETUINT32(pbByte);
+
+ szAtomName[0] = pbByte[SIZE_DATASIZE];
+ szAtomName[1] = pbByte[SIZE_DATASIZE + 1];
+ szAtomName[2] = pbByte[SIZE_DATASIZE + 2];
+ szAtomName[3] = pbByte[SIZE_DATASIZE + 3];
+
+ if(!stricmp(szAtomName, szName))
+ {
+ bVersionedAtom = IsVersionedM4aAtom(szAtomName);
+ bFound = TRUE;
+ }
+ else
+ {
+ if(uAtomSize == 0)
+ pbByte += SIZE_DATASIZE;
+ else
+ pbByte += uAtomSize;
+ }
+ }
+
+ if(bFound)
+ {
+ atomStruct.nDataSize = uAtomSize;
+ atomStruct.nOffset = pbByte - pByteData;
+ atomStruct.bIsVersioned = bVersionedAtom;
+ }
+
+ return bFound;
+}
+
+HX_RESULT
+CMmpLibrary::GetM4aMetaData(M4aAtomSizeAndOffset ilstAtomStruct,
+ BYTE* pByteData,
+ UINT32 itemId)
+{
+ HX_RESULT res = HXR_FAIL;
+
+ UINT32 nStartAtOffset = ilstAtomStruct.nOffset + ATOM_IDSIZE + SIZE_DATASIZE;
+ BYTE* pbByte = pByteData + nStartAtOffset;
+ BYTE* pbEnd = pByteData + ilstAtomStruct.nOffset + ilstAtomStruct.nDataSize;
+
+ if(!pbByte)
+ return res;
+
+ UINT32 uAtomSize = 0;
+ while(pbByte < pbEnd)
+ {
+ char szAtomName[ATOM_IDSIZE + 1];
+ memset(szAtomName, 0, sizeof(szAtomName));
+ uAtomSize = GETUINT32(pbByte);
+
+ szAtomName[0] = pbByte[SIZE_DATASIZE];
+ szAtomName[1] = pbByte[SIZE_DATASIZE + 1];
+ szAtomName[2] = pbByte[SIZE_DATASIZE + 2];
+ szAtomName[3] = pbByte[SIZE_DATASIZE + 3];
+
+ if(strlen(szAtomName))
+ {
+ if(uAtomSize == 0)
+ {
+ break;
+ }
+ else
+ {
+ UINT32 atomId = MP4_BUILD_ATOMID(szAtomName[0], szAtomName[1], szAtomName[2], szAtomName[3]);
+
+ // get atom data .. fill in the atom class structure ... and add to array.
+ BYTE* pData = pbByte + SIZE_DATASIZE + ATOM_IDSIZE + SIZE_DATASIZE + ATOM_IDSIZE;
+
+ UINT32 uDataType = GETUINT32(pData);
+ pData += SIZE_DATATYPE;
+
+ UINT32 uDataModifier = GETUINT32(pData);
+ pData += SIZE_MODIFIER;
+
+ UINT32 nDataSize = pbByte + uAtomSize - pData;
+
+ if (atomId == MP4_BUILD_ATOMID(0xA9,'A','R','T'))
+ {
+ res = SetItemTagData(itemId,
+ CMmpLibrary::ETagArtist,
+ nDataSize,
+ pData);
+ }
+ else if (atomId == MP4_BUILD_ATOMID(0xA9,'a','l','b'))
+ {
+ res = SetItemTagData(itemId,
+ CMmpLibrary::ETagAlbum,
+ nDataSize,
+ pData);
+ }
+ else if (atomId == MP4_BUILD_ATOMID(0xA9,'n','a','m'))
+ {
+ res = SetItemTagData(itemId,
+ CMmpLibrary::ETagName,
+ nDataSize,
+ pData);
+ }
+ else if (atomId == MP4_BUILD_ATOMID('t','r','k','n'))
+ {
+
+ UINT32 id;
+ char binBuf[4];
+ id = pData[3] | (pData[2] << 8) | (pData[1] << 16) | (pData[0] << 24);
+ sprintf(binBuf, "%d", id);
+ res = SetItemTagData(itemId,
+ CMmpLibrary::ETagTrackNum,
+ strlen(binBuf),
+ binBuf);
+ }
+ else if (atomId == MP4_BUILD_ATOMID(0xA9,'g','e','n'))
+ {
+ res = SetItemTagData(itemId,
+ CMmpLibrary::ETagGenre,
+ nDataSize,
+ pData);
+
+ }
+
+ pbByte += uAtomSize;
+ }
+
+ uAtomSize = 0;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return res;
+}
void
CMmpLibrary::ExtractMetaData(const char* pFilename)
@@ -400,7 +602,10 @@
UINT32 nRJMDBufSize = 0;
- // First, see if there is an RJMD buffer in the file
+ //
+ // First, see if there is an RJMD Tag in the file
+ //
+
if (GetRJMDOffsetFromEnd(pFile, &m_ulOrigOffset, &nRJMDBufSize) == HXR_OK)
{
char* pRJMDTag = FindRJMDTag(pFile, m_ulOrigOffset, nRJMDBufSize);
@@ -426,7 +631,11 @@
HX_VECTOR_DELETE(pRJMDTag);
}
}
-
+
+ //
+ // If not there, check for ID3 Tag
+ //
+
if (res != HXR_OK)
{
char* pId3V1Tag = FindId3V1Tag(pFile);
@@ -436,7 +645,27 @@
res = AddItemFromId3V1Tag(pId3V1Tag, itemId);
HX_VECTOR_DELETE(pId3V1Tag);
}
- }
+ }
+
+ //
+ // Last try - check for M4A (AAC) Tag
+ //
+
+ if (res != HXR_OK)
+ {
+ UINT32 uDataSize;
+ struct stat buf;
+ stat(pFilename, &buf);
+
+ BYTE* pMoovTag = FindM4aTag(pFile, buf.st_size, uDataSize);
+
+ if (pMoovTag)
+ {
+ res = AddItemFromM4aTag(pMoovTag, uDataSize, itemId);
+ HX_VECTOR_DELETE(pMoovTag);
+ }
+ }
+
if (HXR_OK == res)
{
@@ -488,6 +717,62 @@
delete [] pReadBuf;
return NULL;
}
+
+BYTE*
+CMmpLibrary::FindM4aTag(FILE* pFile, UINT32 uFileSize, UINT32& uDataSize)
+{
+ char sAtom[ATOM_IDSIZE + SIZE_DATASIZE + 1];
+ BOOL bMoovFound = FALSE;
+ BYTE* byteData = NULL;
+
+ fseek(pFile, 0, SEEK_SET);
+
+ while(!bMoovFound && !feof(pFile))
+ {
+ memset(sAtom, 0, ATOM_IDSIZE + SIZE_DATASIZE + 1);
+ fread(sAtom, sizeof(sAtom) - 1, 1, pFile);
+
+ uDataSize = GETUINT32(sAtom);
+
+ char* szAtomName = &(sAtom[4]);
+ if((stricmp(szAtomName, "moov") == 0) ||
+ (stricmp(szAtomName, "free") == 0))
+ {
+ bMoovFound = TRUE;
+ fseek(pFile, -1*(long)sizeof(sAtom) + 1, SEEK_CUR);
+ }
+ else
+ {
+ if ((uDataSize < sizeof(sAtom)) || (uDataSize > uFileSize))
+ {
+ // not found... Either no metadata or invalid file
+ break;
+ }
+ fseek(pFile, uDataSize - sizeof(sAtom) + 1, SEEK_CUR);
+ uDataSize = 0;
+ }
+ }
+
+ if(bMoovFound && uDataSize)
+ {
+ byteData = new BYTE[uDataSize];
+
+ if(byteData)
+ {
+ if (uDataSize != fread(byteData, 1, uDataSize, pFile))
+ {
+ uDataSize = 0;
+ HX_VECTOR_DELETE(byteData);
+ }
+ }
+ else
+ {
+ uDataSize = 0;
+ }
+ }
+
+ return byteData;
+}
HX_RESULT
CMmpLibrary::AddItemFromId3V1Tag(const char* pId3V1Tag, UINT32& itemId)
@@ -775,5 +1060,59 @@
return res;
}
-
+HX_RESULT
+CMmpLibrary::AddItemFromM4aTag(BYTE* pMoovTag, UINT32 uDataSize, UINT32& itemId)
+{
+ HX_RESULT res = HXR_FAIL;
+
+ M4aAtomSizeAndOffset m_moovAtomStructure;
+ M4aAtomSizeAndOffset m_udtaAtomStructure;
+ M4aAtomSizeAndOffset m_metaAtomStructure;
+ M4aAtomSizeAndOffset m_ilstAtomStructure;
+
+ m_moovAtomStructure.nDataSize = 0;
+ m_moovAtomStructure.nOffset = 0;
+ m_moovAtomStructure.bIsVersioned = FALSE;
+
+ m_udtaAtomStructure.nDataSize = 0;;
+ m_udtaAtomStructure.nOffset = 0;
+ m_udtaAtomStructure.bIsVersioned = FALSE;
+
+ m_metaAtomStructure.nDataSize = 0;;
+ m_metaAtomStructure.nOffset = 0;
+ m_metaAtomStructure.bIsVersioned = FALSE;
+
+ m_ilstAtomStructure.nDataSize = 0;
+ m_ilstAtomStructure.nOffset = 0;
+ m_ilstAtomStructure.bIsVersioned = FALSE;
+
+ m_moovAtomStructure.nDataSize = uDataSize;
+ m_moovAtomStructure.nOffset = 0;
+ m_moovAtomStructure.bIsVersioned = FALSE;
+
+ if(FillM4aNamedAtomSturcture(kudta, m_moovAtomStructure.nOffset, m_moovAtomStructure.bIsVersioned, m_udtaAtomStructure, pMoovTag, uDataSize))
+ {
+ if(FillM4aNamedAtomSturcture(kmeta, m_udtaAtomStructure.nOffset, m_udtaAtomStructure.bIsVersioned, m_metaAtomStructure, pMoovTag, uDataSize))
+ {
+ if(FillM4aNamedAtomSturcture(kilst, m_metaAtomStructure.nOffset, m_metaAtomStructure.bIsVersioned, m_ilstAtomStructure, pMoovTag, uDataSize))
+ {
+ res = AddItem(itemId);
+
+ if (HXR_OK == res)
+ {
+ res = SetItemTagData(itemId,
+ CMmpLibrary::ETagTrackRecord,
+ 0, NULL);
+ }
+
+ if (HXR_OK == res)
+ {
+ res = GetM4aMetaData(m_ilstAtomStructure, pMoovTag, itemId);
+ }
+ }
+ }
+ }
+
+ return res;
+}