⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpi_playlist.c

📁 VC++视频开发实例集锦(包括“远程视频监控”"语音识别系统"等13个经典例子)
💻 C
📖 第 1 页 / 共 5 页
字号:

////////////////////////////////////////////////////////////////////////////////



#include "stdafx.h"
#include "globals.h"
#include "CPI_Playlist.h"
#include "CPI_PlaylistItem.h"
#include "CPI_PlaylistItem_Internal.h"
#include "CPI_Player.h"


#define CPC_TRACKSTACK_BUFFER_QUANTISATION	32
typedef int (__cdecl *wp_SortFN)(const void *elem1, const void *elem2);
int __cdecl exp_CompareStrings(const void *elem1, const void *elem2);
DWORD WINAPI CPI_PlaylistWorkerThreadEP(void* pCookie);
////////////////////////////////////////////////////////////////////////////////
//
typedef struct _CPs_PlaylistWorkerThreadInfo
{
    DWORD m_dwHostThreadID;
    DWORD m_dwCurrentBatchID;

} CPs_PlaylistWorkerThreadInfo;
//
//
typedef struct _CPs_Playlist
{
    CP_HPLAYLISTITEM m_hFirst;
    CP_HPLAYLISTITEM m_hLast;
    CP_HPLAYLISTITEM m_hCurrent;

    CP_HPLAYLISTITEM* m_pTrackStack;
    unsigned int m_iTrackStackSize;
    unsigned int m_iTrackStackBufferSize;
    unsigned int m_iTrackStackCursor;

    HANDLE m_hWorkerThread;
    DWORD m_dwWorkerThreadID;
    CPs_PlaylistWorkerThreadInfo m_WorkerThreadInfo;
    BOOL m_bSyncLoadNextFile;
    BOOL m_bAutoActivateInitial;

} CPs_Playlist;
//
//
typedef enum _CPe_PlayListFileType
{
    pftUnknown,
    pftPLS,
    pftM3U
} CPe_PlayListFileType;
//
typedef struct _CPs_FilenameLLItem
{
    char* m_pcFilename;
    void* m_pNextItem;
} CPs_FilenameLLItem;
//
//
#define CPC_PLAYLISTWORKER_NOTIFYCHUNKSIZE	32
typedef struct _CPs_NotifyChunk
{
    int m_iNumberInChunk;
    CP_HPLAYLISTITEM m_aryItems[CPC_PLAYLISTWORKER_NOTIFYCHUNKSIZE];
    DWORD m_aryBatchIDs[CPC_PLAYLISTWORKER_NOTIFYCHUNKSIZE];

} CPs_NotifyChunk;
//
////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////
//
//
//
CP_HPLAYLIST CPL_CreatePlaylist()
{
    CPs_Playlist* pNewPlaylist = (CPs_Playlist*)malloc(sizeof(CPs_Playlist));
    pNewPlaylist->m_hFirst = NULL;
    pNewPlaylist->m_hLast = NULL;
    pNewPlaylist->m_hCurrent = NULL;

    pNewPlaylist->m_pTrackStack = NULL;
    pNewPlaylist->m_iTrackStackSize = 0;
    pNewPlaylist->m_iTrackStackBufferSize = 0;
    pNewPlaylist->m_iTrackStackCursor = 0;
    pNewPlaylist->m_bSyncLoadNextFile = FALSE;
    pNewPlaylist->m_bAutoActivateInitial = FALSE;

    pNewPlaylist->m_WorkerThreadInfo.m_dwHostThreadID = GetCurrentThreadId();
    pNewPlaylist->m_WorkerThreadInfo.m_dwCurrentBatchID = 0;

    // Create worker thread
    pNewPlaylist->m_hWorkerThread = CreateThread(NULL, 0, CPI_PlaylistWorkerThreadEP, &pNewPlaylist->m_WorkerThreadInfo, 0, &(pNewPlaylist->m_dwWorkerThreadID) );
    CP_ASSERT(pNewPlaylist->m_hWorkerThread);

    return pNewPlaylist;
}
//
//
//
void CPL_DestroyPlaylist(CP_HPLAYLIST hPlaylist)
{
    CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
    CP_CHECKOBJECT(pPlaylist);

    // Stop the worker thread from processing any more pending ID3 reads
    pPlaylist->m_WorkerThreadInfo.m_dwCurrentBatchID++;

    // Request worker thread to shutdown
    PostThreadMessage(pPlaylist->m_dwWorkerThreadID, CPPLWT_TERMINATE, 0, 0);

    // Clean up list
    CPL_Empty(hPlaylist);

    // Delete an unattached active item
    if(pPlaylist->m_hCurrent && CPLII_DECODEHANDLE(pPlaylist->m_hCurrent)->m_bDestroyOnDeactivate)
        CPLII_DestroyItem(pPlaylist->m_hCurrent);

    // Wait for shutdown to actually happen
    WaitForSingleObject(pPlaylist->m_hWorkerThread, INFINITE);
    CloseHandle(pPlaylist->m_hWorkerThread);

    // Remove any read ID3s from our message queue
    {
        MSG msg;
        while(PeekMessage(&msg, NULL, CPPLNM_TAGREAD, CPPLNM_TAGREAD, PM_REMOVE) )
        {
            CPs_NotifyChunk* pChunk = (CPs_NotifyChunk*)msg.wParam;
            int iChunkItemIDX;

            // Add all of the items in the chunk
            for(iChunkItemIDX = 0; iChunkItemIDX < pChunk->m_iNumberInChunk; iChunkItemIDX++)
                CPLII_DestroyItem(pChunk->m_aryItems[iChunkItemIDX]);
            free(pChunk);
        }
    }

    // Clean up object
    free(pPlaylist);
}
//
//
//
void CPL_UnlinkItem(CP_HPLAYLIST hPlaylist, CP_HPLAYLISTITEM hItem)
{
    CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
    CPs_PlaylistItem* pItemToUnlink = CPLII_DECODEHANDLE(hItem);
    CP_CHECKOBJECT(pPlaylist);

    // Remove item from list
    if(pItemToUnlink->m_hPrev)
        CPLII_DECODEHANDLE(pItemToUnlink->m_hPrev)->m_hNext = pItemToUnlink->m_hNext;
    else
    {
        CP_ASSERT(pPlaylist->m_hFirst == hItem);
        pPlaylist->m_hFirst = pItemToUnlink->m_hNext;
    }

    if(pItemToUnlink->m_hNext)
        CPLII_DECODEHANDLE(pItemToUnlink->m_hNext)->m_hPrev = pItemToUnlink->m_hPrev;
    else
    {
        CP_ASSERT(pPlaylist->m_hLast == hItem);
        pPlaylist->m_hLast = pItemToUnlink->m_hPrev;
    }
}
//
//
//
void CPL_Empty(CP_HPLAYLIST hPlaylist)
{
    CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
    CP_HPLAYLISTITEM hCursor, hNext;

    CP_CHECKOBJECT(pPlaylist);

    // Stop the worker thread from processing any more pending ID3 reads
    pPlaylist->m_WorkerThreadInfo.m_dwCurrentBatchID++;

    // Unlink the active item
    if(pPlaylist->m_hCurrent)
    {
        // This is the active item - clear it's next and prev entries and mark it
        // so that it's destroyed when activation next changes
        CPs_PlaylistItem* pActiveItem = CPLII_DECODEHANDLE(pPlaylist->m_hCurrent);
        if(pActiveItem->m_bDestroyOnDeactivate == FALSE)
        {
            CPL_UnlinkItem(hPlaylist, pPlaylist->m_hCurrent);
            pActiveItem->m_hNext = NULL;
            pActiveItem->m_hPrev = NULL;
            pActiveItem->m_bDestroyOnDeactivate = TRUE;
            CPL_cb_OnPlaylistActivationChange(pPlaylist->m_hCurrent, FALSE);
            pActiveItem->m_iCookie = CPC_INVALIDITEM;
        }
    }

    // Callback
    CPL_cb_OnPlaylistEmpty();

    // Clean up items
    hCursor = pPlaylist->m_hFirst;
    while(hCursor)
    {
        hNext = CPLI_Next(hCursor);
        CPLII_DestroyItem(hCursor);
        hCursor = hNext;
    }

    // Reset state
    pPlaylist->m_hFirst = NULL;
    pPlaylist->m_hLast = NULL;

    // Clean up the trackstack
    if(pPlaylist->m_pTrackStack)
        free(pPlaylist->m_pTrackStack);
    pPlaylist->m_pTrackStack = NULL;
    pPlaylist->m_iTrackStackSize = 0;
    pPlaylist->m_iTrackStackBufferSize = 0;
    pPlaylist->m_iTrackStackCursor = 0;
}
//
//
//
void CPL_AddSingleFile_pt2(CP_HPLAYLIST hPlaylist, CP_HPLAYLISTITEM hNewFile, const DWORD dwBatchID)
{
    CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
    const char* pcPath = CPLI_GetPath(hNewFile);

    CP_CHECKOBJECT(pPlaylist);

    // Batch has changed since this message was sent
    if(dwBatchID != pPlaylist->m_WorkerThreadInfo.m_dwCurrentBatchID)
    {
        CPLII_DestroyItem(hNewFile);
        return;
    }

    // If items are only allowed once - look for another instance of this item
    // and skip this add if it is found
    if(options.allow_file_once_in_playlist)
    {
        CP_HPLAYLISTITEM hCursor;
        hCursor = pPlaylist->m_hFirst;
        while(hCursor)
        {
            // Is this item in the list already?
            if(stricmp(CPLII_DECODEHANDLE(hCursor)->m_pcPath, pcPath) == 0)
            {
                CPLII_DestroyItem(hNewFile);
                return;
            }

            hCursor = CPLI_Next(hCursor);
        }
    }

    // Add item to the list
    CPLII_DECODEHANDLE(hNewFile)->m_hPrev = pPlaylist->m_hLast;
    if(pPlaylist->m_hLast)
        CPLII_DECODEHANDLE(pPlaylist->m_hLast)->m_hNext = hNewFile;
    pPlaylist->m_hLast = hNewFile;
    if(pPlaylist->m_hFirst == NULL)
        pPlaylist->m_hFirst = hNewFile;

    // If there is no track name (ID3 read off or failed) - create one from the path
    if(CPLII_DECODEHANDLE(hNewFile)->m_pcTrackName == NULL)
    {
        int iNumChars;
        int iCharIDX;
        int iLastSlashIDX = CPC_INVALIDCHAR;
        int iLastDotIDX = CPC_INVALIDCHAR;
        int iLastCharIDX = CPC_INVALIDCHAR;
		if(strnicmp(pcPath,CIC_HTTPHEADER,strlen(CIC_HTTPHEADER)) == 0)
            iLastCharIDX = strlen(pcPath);
		else
        for(iCharIDX=0; pcPath[iCharIDX]; iCharIDX++)
        {
            if(pcPath[iCharIDX] == '\\')
                iLastSlashIDX = iCharIDX;
            if(pcPath[iCharIDX] == '.')
                iLastDotIDX = iCharIDX;
            iLastCharIDX = iCharIDX;
        }

        // Correct indices
        if(iLastSlashIDX == CPC_INVALIDCHAR)
            iLastSlashIDX = 0;
        else
            iLastSlashIDX++; // We want the char after the last slash
        if(iLastDotIDX == CPC_INVALIDCHAR || iLastDotIDX < iLastSlashIDX)
            iLastDotIDX = iLastCharIDX;
        else
            iLastDotIDX--; // We want the string up to the char before the last dot

        // Create title buffer
        iNumChars = (iLastDotIDX-iLastSlashIDX)+1;
        CPLII_DECODEHANDLE(hNewFile)->m_pcTrackName = (char*)malloc(iNumChars+1);
        memcpy(CPLII_DECODEHANDLE(hNewFile)->m_pcTrackName, pcPath+iLastSlashIDX, iNumChars);
        CPLII_DECODEHANDLE(hNewFile)->m_pcTrackName[iNumChars] = '\0';
    }

    // Add to track stack
    CPL_Stack_Append(hPlaylist, hNewFile);

    // Callback
    CPL_cb_OnPlaylistAppend(hNewFile);
}
//
//
//
void CPL_AddSingleFile(CP_HPLAYLIST hPlaylist, const char* pcPath, const char* pcTitle)
{
    CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
    CP_HPLAYLISTITEM hNewFile;
    CP_CHECKOBJECT(pPlaylist);

    hNewFile = CPLII_CreateItem(pcPath);

    // There was a title passed - setup the item accordingly
    if(pcTitle && pcTitle[0])
        STR_AllocSetString(&CPLII_DECODEHANDLE(hNewFile)->m_pcTrackName, pcTitle, FALSE);

    // Defer this add to the worker thread if we are reading tags
    if(options.read_id3_tag && options.read_id3_tag_in_background && !pPlaylist->m_bSyncLoadNextFile)
    {
        while(!PostThreadMessage(pPlaylist->m_dwWorkerThreadID, CPPLWT_READTAG, (WPARAM)pPlaylist->m_WorkerThreadInfo.m_dwCurrentBatchID, (LPARAM)hNewFile))
        { 
			Sleep(50); 
		}       
		if(pPlaylist->m_bAutoActivateInitial && stricmp(pcPath, options.initial_file) == 0)
            PostThreadMessage(pPlaylist->m_dwWorkerThreadID, CPPLWT_SETACTIVE, (WPARAM)pPlaylist->m_WorkerThreadInfo.m_dwCurrentBatchID, (LPARAM)hNewFile);
    }
    else
    {
        pPlaylist->m_bSyncLoadNextFile = FALSE;
        if(options.read_id3_tag)
            CPLI_ReadTag(hNewFile);

        // If we didn't get a track length from the tag - work it out
        if(CPLI_GetTrackLength(hNewFile) == 0
                && options.work_out_track_lengths)
        {
            CPLI_CalculateLength(hNewFile);
        }

        CPL_AddSingleFile_pt2(hPlaylist, hNewFile, pPlaylist->m_WorkerThreadInfo.m_dwCurrentBatchID);
    }
}
//
//
//
void CPL_HandleAsyncNotify(CP_HPLAYLIST hPlaylist, WPARAM wParam, LPARAM lParam)
{
    CPs_NotifyChunk* pChunk = (CPs_NotifyChunk*)wParam;
    int iChunkItemIDX;

    // Add all of the items in the chunk
    CLV_BeginBatch(globals.m_hPlaylistViewControl);
    for(iChunkItemIDX = 0; iChunkItemIDX < pChunk->m_iNumberInChunk; iChunkItemIDX++)
        CPL_AddSingleFile_pt2(globals.m_hPlaylist, pChunk->m_aryItems[iChunkItemIDX], pChunk->m_aryBatchIDs[iChunkItemIDX]);
    CLV_EndBatch(globals.m_hPlaylistViewControl);

    // Cleanup
    free(pChunk);
}
//
//
//
void CPL_RemoveDuplicates(CP_HPLAYLIST hPlaylist)
{
    CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
    CP_HPLAYLISTITEM hCursor;
    CP_CHECKOBJECT(pPlaylist);

    // Scan the playlist removing duplicates
    hCursor = pPlaylist->m_hFirst;
    while(hCursor)
    {
        CP_HPLAYLISTITEM hCursor_Scan;

        // Look for duplicates after this item (as all items will be scanned
        // in this way there is no need to look for duplicates before this item)
        hCursor_Scan = CPLI_Next(hCursor);
        while(hCursor_Scan)
        {
            // Is this a duplicate
            if(stricmp(	CPLII_DECODEHANDLE(hCursor_Scan)->m_pcPath,
                        CPLII_DECODEHANDLE(hCursor)->m_pcPath) == 0)
            {
                CPL_RemoveItem(hPlaylist, hCursor_Scan);

                // Items before the current are already unique - stop scanning

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -