Ver código fonte

V2.1.9 -
1.优化音频文件播放。
2.修复杂音问题。
3.修复RTSP延时问题。

huihui 6 meses atrás
pai
commit
30ae0df6ce

+ 6 - 0
.gitignore

@@ -8,3 +8,9 @@ bin64/VideoPlayer
 build/
 module/VideoPlayer/lib/SDL2
 module/VideoPlayer/lib/ffmpeg
+bin/win64/VideoPlayer.exe
+bin/win64/Debug/VideoPlayer.exe
+bin/win64/Debug/VideoPlayer.ilk
+bin/win64/Debug/VideoPlayer.pdb
+bin/win64/Release/VideoPlayer.exe
+.vscode/settings.json

+ 14 - 1
.vscode/launch.json

@@ -24,7 +24,20 @@
             "stopAtEntry": false,
             "cwd": "${workspaceRoot}/bin/win64/",
             "environment": [{"name":"PATH","value":"C:/Qt/Qt5.13.2/5.13.2/msvc2017_64/bin"}],
-            "console": "externalTerminal"
+            // "console": "externalTerminal"
+            "console": "internalConsole" //在 VSCode 内部的调试控制台中显示输出,这个控制台只能在调试会话期间使用。
+        },
+        { 
+            "name": "VideoPlayer(Release_x64)",
+            "type": "cppvsdbg",
+            "request": "launch",
+            "program": "${workspaceRoot}/bin/win64/Release/VideoPlayer.exe",
+            "args": [],
+            "stopAtEntry": false,
+            "cwd": "${workspaceRoot}/bin/win64/",
+            "environment": [{"name":"PATH","value":"D:/Qt/Qt5.13.2/5.13.2/msvc2017_64/bin"}],
+            // "console": "externalTerminal"
+            "console": "internalConsole" //在 VSCode 内部的调试控制台中显示输出,这个控制台只能在调试会话期间使用。
         }
     ]
 }

+ 23 - 17
CMakeLists.txt

@@ -33,15 +33,28 @@ elseif(WIN32)
 
     message("current platform: Windows ")
 
-    set(QT_DIR_ROOT C:/Qt/Qt5.13.2/5.13.2)
+    #指定Qt安装目录
+    set(QT_DIR_ROOT 
+            C:/Qt/Qt5.13.2/5.13.2
+            D:/Qt/Qt5.13.2/5.13.2)
     
     if(CMAKE_CL_64)    #CMAKE的内建变量,如果是true,就说明编译器的64位的,自然可以编译64bit的程序
+        set(QT_DIR_NAME msvc2017_64)
+
         # set(CMAKE_PREFIX_PATH ${QT_DIR_ROOT}/msvc2017_64)
-        list(APPEND CMAKE_PREFIX_PATH ${QT_DIR_ROOT}/msvc2017_64)
+        # list(APPEND CMAKE_PREFIX_PATH ${QT_DIR_ROOT}/msvc2017_64)
     else()
-        # set(CMAKE_PREFIX_PATH ${QT_DIR_ROOT}/msvc2017)
-        list(APPEND CMAKE_PREFIX_PATH ${QT_DIR_ROOT}/msvc2017)
+        set(QT_DIR_NAME msvc2017)
     endif()
+
+    foreach(item ${QT_DIR_ROOT})
+        set(QT_DIR_PATH ${item}/${QT_DIR_NAME})
+        message(STATUS "item is ${QT_DIR_PATH}")
+        if(EXISTS ${QT_DIR_PATH})
+            list(APPEND CMAKE_PREFIX_PATH ${QT_DIR_PATH})
+        endif()
+    endforeach()
+
 else()
 
     message("current platform: unkonw ")
@@ -61,7 +74,7 @@ endif()
 
 
 # find_package(<库名> <版本号> EXACT COMPONENTS <组件名1> ... <组件名n> REQUIRED)
-find_package(Qt5 5.13.2 COMPONENTS Widgets Network WebSockets Concurrent REQUIRED)
+find_package(Qt5 5.13.2 COMPONENTS Widgets Network Concurrent REQUIRED)
  
 #CMAKE_ARCHIVE_OUTPUT_DIRECTORY:默认存放静态库的文件夹位置;
 #CMAKE_LIBRARY_OUTPUT_DIRECTORY:默认存放动态库的文件夹位置;
@@ -84,13 +97,7 @@ endif()
 # set the include files
 set(PRO_CODE_INC
         ${CMAKE_CURRENT_SOURCE_DIR}/src
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/SendRtmp_Dll/src
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/SendRtmp_TestDll/src
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/ipc_operation/media_utils
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/sdk_api_operation
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/t31-sample
         ${CMAKE_CURRENT_SOURCE_DIR}/src/module
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/module/Audio
         ${CMAKE_CURRENT_SOURCE_DIR}/module/DragAbleWidget
         )
 include_directories(${PRO_CODE_INC})
@@ -100,7 +107,6 @@ file(GLOB_RECURSE ALL_SOURCE
         ${CMAKE_CURRENT_SOURCE_DIR}/module/DragAbleWidget/*.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c
         ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/Base/*.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/src/Widget/*.cpp
         )
   
@@ -118,10 +124,10 @@ file(GLOB_RECURSE ALL_SOURCE
 #         src/*.hpp
 #         src/*.h)
 
-qt5_add_resources(qrc_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/resources.qrc)
-message("ALL_SOURCE:"${ALL_SOURCE})
-# add_executable(${PROJECT_NAME} ${ALL_SOURCE} ${qrc_FILES})
-add_executable(${PROJECT_NAME} ${ALL_SOURCE})
+qt5_add_resources(qrc_FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/resources.qrc)
+# message("ALL_SOURCE:"${ALL_SOURCE})
+add_executable(${PROJECT_NAME} ${ALL_SOURCE} ${qrc_FILES})
+# add_executable(${PROJECT_NAME} ${ALL_SOURCE})
 
 #### add videoplayer module ###
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/module/VideoPlayer)
@@ -135,7 +141,7 @@ include_directories(${PRO_CODE_INC})
 
 target_link_libraries(${PROJECT_NAME}
         WS2_32.lib AdvAPI32.lib winmm.lib User32.lib GDI32.lib Strmiids.lib
-        Qt5::Core Qt5::Widgets Qt5::Network Qt5::WebSockets  Qt5::Concurrent)
+        Qt5::Core Qt5::Widgets Qt5::Network  Qt5::Concurrent)
 #target_link_libraries(${PROJECT_NAME}
 #        -lavformat
 #        -lavcodec

+ 7 - 0
README.md

@@ -23,6 +23,13 @@ PS:记得将ffmpeg/bin目录下的dll文件拷贝到编译生成的exe所在的
 
 
 # PS:从版本2开始,ffmpeg版本升级到4.1。无需手动拷贝dll的操作,且工程已可以自动判断编译器位数。
+版本二更新日志:  
+【V2.1.9】 2024-12-25  
+Qt5.13.2(vs2017/mingw) + ffmpeg4.1 + SDL2  
+1.优化音频文件播放。  
+2.修复杂音问题。  
+3.修复RTSP延时问题。  
+
 【V2.1.8】 2024-12-20  
 Qt5.13.2(vs2017/mingw) + ffmpeg4.1 + SDL2  
 1.工程加入cmake管理,支持用vscode编译。  

+ 0 - 2
VideoPlayer.pro

@@ -39,14 +39,12 @@ SOURCES += \
     src/Widget/mymessagebox_withTitle.cpp \
     src/main.cpp \
     src/AppConfig.cpp \
-    src/Base/FunctionTransfer.cpp \
     src/MainWindow.cpp \
     src/Widget/ShowVideoWidget.cpp \
     src/Widget/VideoSlider.cpp
 
 HEADERS  += \
     src/AppConfig.h \
-    src/Base/FunctionTransfer.h \
     src/MainWindow.h \
     src/Widget/SetVideoUrlDialog.h \
     src/Widget/ShowVideoWidget.h \

+ 0 - 5
module/VideoPlayer/CMakeLists.txt

@@ -5,12 +5,7 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib)
 
 file(GLOB_RECURSE ALL_SOURCE
         ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/EventHandle/*.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/LogWriter/*.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/Mutex/*.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/src/VideoPlayer/*.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/VideoPlayer/Audio/*.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/src/VideoPlayer/Video/*.cpp
         )
 
 message("ALL_SOURCE:"${ALL_SOURCE})

+ 14 - 14
module/VideoPlayer/VideoPlayer.pri

@@ -4,25 +4,25 @@ QMAKE_CXXFLAGS += -std=c++11
 INCLUDEPATH += $$PWD/src
 
 SOURCES +=  \
-    $$PWD/src/Mutex/Cond.cpp \
-    $$PWD/src/Mutex/Mutex.cpp \
-    $$PWD/src/LogWriter/LogWriter.cpp \
     $$PWD/src/VideoPlayer/VideoPlayer.cpp \
-    $$PWD/src/VideoPlayer/Video/VideoFrame.cpp \
-    $$PWD/src/VideoPlayer/Video/VideoPlayer_VideoThread.cpp \
-    $$PWD/src/VideoPlayer/Audio/VideoPlayer_AudioThread.cpp \
-    $$PWD/src/VideoPlayer/Audio/PcmVolumeControl.cpp \
-    $$PWD/src/EventHandle/VideoPlayerEventHandle.cpp \
+    $$PWD/src/frame/VideoFrame/VideoFrame.cpp \
+    $$PWD/src/frame/AudioFrame/PCMFrame.cpp \
+    $$PWD/src/VideoPlayer/VideoPlayer_VideoThread.cpp \
+    $$PWD/src/VideoPlayer/VideoPlayer_AudioThread.cpp \
+    $$PWD/src/PcmPlayer/PcmVolumeControl.cpp \
+    $$PWD/src/PcmPlayer/PcmPlayer_SDL.cpp \
+    $$PWD/src/PcmPlayer/PcmPlayer.cpp \
+    $$PWD/src/util/thread.cpp \
     $$PWD/src/types.cpp
 
 HEADERS  += \
-    $$PWD/src/Mutex/Cond.h \
-    $$PWD/src/Mutex/Mutex.h \
-    $$PWD/src/LogWriter/LogWriter.h \
     $$PWD/src/VideoPlayer/VideoPlayer.h \
-    $$PWD/src/VideoPlayer/Video/VideoFrame.h \
-    $$PWD/src/VideoPlayer/Audio/PcmVolumeControl.h \
-    $$PWD/src/EventHandle/VideoPlayerEventHandle.h \
+    $$PWD/src/frame/VideoFrame/VideoFrame.h \
+    $$PWD/src/frame/AudioFrame/PCMFrame.h \
+    $$PWD/src/PcmPlayer/PcmVolumeControl.h \
+    $$PWD/src/PcmPlayer/PcmPlayer_SDL.h \
+    $$PWD/src/PcmPlayer/PcmPlayer.cpp \
+    $$PWD/src/util/thread.h \
     $$PWD/src/types.h
 
 ### lib ### Begin

+ 0 - 6
module/VideoPlayer/src/EventHandle/VideoPlayerEventHandle.cpp

@@ -1,6 +0,0 @@
-#include "VideoPlayerEventHandle.h"
-
-VideoPlayerCallBack::~VideoPlayerCallBack()
-{
-
-}

+ 0 - 29
module/VideoPlayer/src/EventHandle/VideoPlayerEventHandle.h

@@ -1,29 +0,0 @@
-#ifndef VIDEOPLAYEREVENTHANDLE_H
-#define VIDEOPLAYEREVENTHANDLE_H
-
-#include "types.h"
-#include "frame/VideoFrame/VideoFrame.h"
-
-class VideoPlayerCallBack
-{
-public:
-    ~VideoPlayerCallBack();
-
-    ///打开文件失败
-    virtual void onOpenVideoFileFailed(const int &code = 0) = 0;
-
-    ///打开sdl失败的时候回调此函数
-    virtual void onOpenSdlFailed(const int &code) = 0;
-
-    ///获取到视频时长的时候调用此函数
-    virtual void onTotalTimeChanged(const int64_t &uSec) = 0;
-
-    ///播放器状态改变的时候回调此函数
-    virtual void onPlayerStateChanged(const VideoPlayerState &state, const bool &hasVideo, const bool &hasAudio) = 0;
-
-    ///播放视频,此函数不宜做耗时操作,否则会影响播放的流畅性。
-    virtual void onDisplayVideo(VideoFramePtr videoFrame) = 0;
-
-};
-
-#endif // VIDEOPLAERYEVENTHANDLE_H

+ 0 - 243
module/VideoPlayer/src/LogWriter/LogWriter.cpp

@@ -1,243 +0,0 @@
-#include "LogWriter.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "types.h"
-
-#ifdef WIN32
-#include <direct.h>
-#include <io.h>                      //C (Windows)    access
-#define R_OK 0
-#else
-#include <unistd.h>                  //C (Linux)      access
-#endif
-
-#if defined(WIN32)
-    #include <WinSock2.h>
-    #include <Windows.h>
-static DWORD WINAPI thread_Func(LPVOID pM)
-#else
-    #include <sys/time.h>
-    #include <stdio.h>
-    #include <time.h>
-    #include <stdlib.h>
-    #include <unistd.h>
-static void *thread_Func(void *pM)
-#endif
-{
-    LogWriter *pointer = (LogWriter*)pM;
-    pointer->run();
-
-    return 0;
-}
-
-#define TMPBUFFERLEN (1024 * 1024 * 3)
-
-LogWriter::LogWriter()
-{
-    mCondition = new Cond;
-
-    mTmpBuffer = new char[TMPBUFFERLEN];
-
-#if defined(WIN32)
-     HANDLE handle = CreateThread(NULL, 0, thread_Func, this, 0, NULL);
-#else
-    pthread_t thread1;
-    pthread_create(&thread1,NULL,thread_Func,this);
-#endif
-}
-
-LogWriter::~LogWriter()
-{
-    if (mTmpBuffer != NULL)
-    {
-        delete mTmpBuffer;
-        mTmpBuffer = NULL;
-    }
-
-    if (mCondition != NULL)
-    {
-        delete mCondition;
-        mCondition = NULL;
-    }
-}
-
-void LogWriter::addLogNode(const LogInfoNode &node)
-{
-    mCondition->Lock();
-    mLogNodeList.push_back(node);
-    mCondition->Signal();
-    mCondition->Unlock();
-}
-
-void LogWriter::writeLog(int cameraId, const std::string &str)
-{
-
-    LogInfoNode node;
-    node.cameraId = cameraId;
-    node.mCreateTime =  getTimeStamp_MilliSecond();
-
-#if defined(WIN32)
-    SYSTEMTIME sys;
-    GetLocalTime( &sys );
-
-    memset(mTmpBuffer, 0x0, TMPBUFFERLEN);
-
-    sprintf(mTmpBuffer,"[%d-%02d-%02d %02d:%02d:%02d.%03d] %s\n",
-            sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond, sys.wMilliseconds, str.c_str());
-
-    node.logStr = mTmpBuffer;
-
-#else
-    struct timeval    tv;
-    struct timezone tz;
-
-    struct tm         *p;
-
-    gettimeofday(&tv, &tz);
-    p = localtime(&tv.tv_sec);
-
-
-    memset(mTmpBuffer, 0x0, TMPBUFFERLEN);
-
-//    memset(node.time,0x0,32);
-//    sprintf(node.time,"%d-%02d-%02d %02d:%02d:%02d.%03d",1900+p->tm_year, 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, tv.tv_usec);
-
-    sprintf(mTmpBuffer,"[%d-%02d-%02d %02d:%02d:%02d.%03d] %s\n",
-            1900+p->tm_year, 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, tv.tv_usec, str.c_str());
-
-    node.logStr = mTmpBuffer;
-
-#endif
-
-    addLogNode(node);
-
-//    if (cameraId == WRITE_LOG_ID_MAIN)
-//    {
-//        fprintf(stderr, "******:");
-//    }
-
-//    if (cameraId == WRITE_LOG_ID_MAIN)
-    {
-
-#if defined(WIN32)
-        fprintf(stderr,"[%d-%02d-%02d %02d:%02d:%02d.%03d] %s\n",
-                sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond, sys.wMilliseconds, str.c_str());
-
-#else
-        fprintf(stderr,"[%d-%02d-%02d %02d:%02d:%02d.%03d] %s",
-                1900+p->tm_year, 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, tv.tv_usec, str.c_str());
-#endif
-    }
-
-}
-
-void LogWriter::run()
-{
-
-    while(1)
-    {
-        mCondition->Lock();
-
-        if (mLogNodeList.empty())
-        {
-            mCondition->Wait();
-        }
-
-        bool isNeedWriteToFile = false;
-        if (mLogNodeList.size() >= 10)//日志文件超过10条 则写入文件
-        {
-            isNeedWriteToFile = true;
-        }
-        else
-        {
-            uint64_t startTime = mLogNodeList.front().mCreateTime;
-            uint64_t currentTime = getTimeStamp_MilliSecond();
-
-            if ((currentTime - startTime) > (10000)) //日志数据最迟10秒写入文件
-            {
-                isNeedWriteToFile = true;
-            }
-        }
-
-        if(isNeedWriteToFile)
-        {
-            std::list<LogInfoNode> LogNodeList = mLogNodeList;
-            mLogNodeList.clear();
-
-            mCondition->Unlock();
-
-            while(!LogNodeList.empty())
-            {
-                LogInfoNode node = LogNodeList.front();
-                LogNodeList.pop_front();
-
-#ifdef WIN32
-                char logDirName[20] = {0};
-                sprintf(logDirName,"log\\%d",node.cameraId);
-                ///如果log目录不存在 则创建
-                if (access(logDirName, R_OK)!=0)
-                {
-//                        _mkdir(logDirName);
-                    char cmd[32] = {0};
-                    sprintf(cmd,"mkdir %s",logDirName);
-                    system(cmd);
-                }
-#else
-                char logDirName[20] = {0};
-                sprintf(logDirName,"log/%d",node.cameraId);
-                ///如果log目录不存在 则创建
-                if (access(logDirName,R_OK)!=0)
-                {
-                    char cmd[32] = {0};
-                    sprintf(cmd,"mkdir %s -p",logDirName);
-                    system(cmd);
-                }
-#endif
-
-                ///一个文件最多5M 超过5M则创建下一个文件
-                int index = 0;
-                char fileName[36];
-                while(1)
-                {
-                    memset(fileName,0x0,36);
-                    sprintf(fileName,"log/%d/logfile_%d",node.cameraId,index++);
-                    if (access(fileName, R_OK)==0)
-                    {
-                        FILE * fp = fopen(fileName, "r");
-                        fseek(fp, 0L, SEEK_END);
-                        int size = ftell(fp);
-                        fclose(fp);
-                        if (size < 5*1024*1024) //小于5M则可以写
-                        {
-                            break;
-                        }
-                    }
-                    else
-                    {
-                        break;
-                    }
-                }
-
-                FILE * fp = fopen(fileName, "at+");
-                if (fp == NULL)
-                {
-                    fprintf(stderr,"写日志失败,请确保你有足够的权限写!\n");
-                }
-                else
-                {
-                    fwrite(node.logStr.c_str(),1,node.logStr.size(),fp);
-                    fclose(fp);
-                }
-            }
-        }
-        else
-        {
-            mCondition->Unlock();
-            mSleep(5000);
-            continue;
-        }
-    }
-}

+ 0 - 58
module/VideoPlayer/src/LogWriter/LogWriter.h

@@ -1,58 +0,0 @@
-#ifndef LOGWRITER_H
-#define LOGWRITER_H
-
-#include <time.h>
-#include <string.h>
-#include <list>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string>
-
-#include "Mutex/Cond.h"
-
-#define LOGSTR_MAX_LENGTH 512
-
-/**
- * @brief The LogWriter class
- * 写日志类 负责定时将日志信息写入文件  并管理日志文件
- */
-
-class LogWriter
-{
-public:
-    struct LogInfoNode
-    {
-        int cameraId;
-        uint64_t mCreateTime; //创建的时间(用来判断过了多久)
-        std::string logStr;
-
-        LogInfoNode()
-        {
-            cameraId = 0;
-    //        memset(time, 0x0, 32);
-    //        memset(logStr, 0x0, LOGSTR_MAX_LENGTH);
-        }
-
-    };
-
-    LogWriter();
-    ~LogWriter();
-
-    void writeLog(int cameraId, const std::string &str);
-
-    void run();
-
-private:
-    char fileName[20];
-
-    char *mTmpBuffer;
-
-    void addLogNode(const LogInfoNode &node);
-
-    std::list<LogInfoNode> mLogNodeList; //数据队列
-    Cond *mCondition;
-
-};
-
-#endif // LOGWRITER_H

+ 0 - 98
module/VideoPlayer/src/Mutex/Cond.cpp

@@ -1,98 +0,0 @@
-#include "Cond.h"
-
-Cond::Cond()
-{
-#if defined(WIN32) && !defined(MINGW)
-    InitializeCriticalSection(&m_mutex);
-    InitializeConditionVariable(&m_cond);
-#else
-    pthread_mutex_init(&m_mutex, NULL);
-    pthread_cond_init(&m_cond, NULL);
-#endif
-
-}
-
-Cond::~Cond()
-{
-#if defined(WIN32) && !defined(MINGW)
-    DeleteCriticalSection(&m_mutex);
-#else
-    pthread_mutex_destroy(&m_mutex);
-    pthread_cond_destroy(&m_cond);
-#endif
-
-}
-
-//加锁
-int Cond::Lock()
-{
-#if defined(WIN32) && !defined(MINGW)
-    EnterCriticalSection(&m_mutex);
-    return 0;
-#else
-    return pthread_mutex_lock(&m_mutex);
-#endif
-
-}
-
-//解锁
-int Cond::Unlock()
-{
-#if defined(WIN32) && !defined(MINGW)
-    LeaveCriticalSection(&m_mutex);
-    return 0;
-#else
-    return pthread_mutex_unlock(&m_mutex);
-#endif
-}
-
-int Cond::Wait()
-{
-#if defined(WIN32) && !defined(MINGW)
-    DWORD ret = SleepConditionVariableCS((PCONDITION_VARIABLE)&m_cond, &m_mutex, INFINITE);
-#else
-    int ret = pthread_cond_wait(&m_cond, &m_mutex);
-#endif
-
-    return ret;
-
-}
-
-//固定时间等待
-int Cond::TimedWait(int second)
-{
-#if defined(WIN32) && !defined(MINGW)
-    SleepConditionVariableCS((PCONDITION_VARIABLE)&m_cond, &m_mutex, second*1000);
-    return 0;
-#else
-    struct timespec abstime;
-    //获取从当前时间,并加上等待时间, 设置进程的超时睡眠时间
-    clock_gettime(CLOCK_REALTIME, &abstime);
-    abstime.tv_sec += second;
-    return pthread_cond_timedwait(&m_cond, &m_mutex, &abstime);
-#endif
-
-}
-
-int Cond::Signal()
-{
-#if defined(WIN32) && !defined(MINGW)
-    int ret = 0;
-    WakeConditionVariable((PCONDITION_VARIABLE)&m_cond);
-#else
-    int ret = pthread_cond_signal(&m_cond);
-#endif
-    return ret;
-}
-
-//唤醒所有睡眠线程
-int Cond::Broadcast()
-{
-#if defined(WIN32) && !defined(MINGW)
-    WakeAllConditionVariable((PCONDITION_VARIABLE)&m_cond);
-    return 0;
-#else
-    return pthread_cond_broadcast(&m_cond);
-#endif
-
-}

+ 0 - 55
module/VideoPlayer/src/Mutex/Cond.h

@@ -1,55 +0,0 @@
-#ifndef COND_H
-#define COND_H
-
-/// 注意Mingw的话使用的是linux下的api pthread
-/// 没有_MSC_VER这个宏 我们就认为他用的是mingw编译器
-
-#ifndef _MSC_VER
-#define MINGW
-#endif
-
-#if defined(WIN32) && !defined(MINGW)
-    #include <WinSock2.h>
-    #include <Windows.h>
-#else
-    #include <pthread.h>
-    #include <time.h>
-#endif
-
-class Cond
-{
-public:
-    Cond();
-    ~Cond();
-
-    //上锁
-    int Lock();
-
-    //解锁
-    int Unlock();
-
-    //
-    int Wait();
-
-    //固定时间等待
-    int TimedWait(int second);
-
-    //
-    int Signal();
-
-    //唤醒所有睡眠线程
-    int Broadcast();
-
-private:
-
-#if defined(WIN32) && !defined(MINGW)
-    CRITICAL_SECTION m_mutex;
-    RTL_CONDITION_VARIABLE m_cond;
-#else
-    pthread_mutex_t m_mutex;
-    pthread_cond_t m_cond;
-#endif
-
-};
-
-#endif // MUTEX_H

+ 0 - 44
module/VideoPlayer/src/Mutex/Mutex.cpp

@@ -1,44 +0,0 @@
-#include "Mutex.h"
-
-Mutex::Mutex()
-{
-#if defined(WIN32)
-    m_mutex = ::CreateMutex(NULL, FALSE, NULL);
-#else
-    pthread_mutex_init(&mutex, NULL);
-#endif
-
-}
-
-Mutex::~Mutex()
-{
-#if defined(WIN32)
-    ::CloseHandle(m_mutex);
-#else
-     pthread_mutex_destroy(&mutex);
-#endif
-
-}
-
-int Mutex::Lock() const
-{
-#if defined(WIN32)
-    DWORD ret = WaitForSingleObject(m_mutex, INFINITE);
-#else
-    int ret = pthread_mutex_lock((pthread_mutex_t*)&mutex);
-#endif
-
-    return ret;
-
-}
-
-int Mutex::Unlock() const
-{
-#if defined(WIN32)
-    bool ret = ::ReleaseMutex(m_mutex);
-#else
-    int ret = pthread_mutex_unlock((pthread_mutex_t*)&mutex);
-#endif
-    return ret;
-}
-

+ 0 - 35
module/VideoPlayer/src/Mutex/Mutex.h

@@ -1,35 +0,0 @@
-#ifndef MUTEX_H
-#define MUTEX_H
-
-
-#if defined(WIN32)
-    #include <WinSock2.h>
-    #include <Windows.h>
-//#elif defined(Q_OS_LINUX)
-#else
-    #include <pthread.h>
-#endif
-
-class Mutex
-{
-public:
-    Mutex();
-    ~Mutex();
-
-    //确保拥有互斥对象的线程对被保护资源的独自访问
-    int Lock() const;
-
-    //释放当前线程拥有的互斥对象,以使其它线程可以拥有互斥对象,对被保护资源进行访问
-    int Unlock() const;
-
-private:
-
-#if defined(WIN32)
-     HANDLE m_mutex;
-#else
-    pthread_mutex_t mutex;
-#endif
-
-};
-
-#endif // MUTEX_H

+ 65 - 35
module/VideoPlayer/src/PcmPlayer/PcmPlayer.cpp

@@ -1,12 +1,14 @@
 #include "PcmPlayer.h"
 
-#include "PcmVolumeControl.h"
-
 #include <stdio.h>
+#include <math.h>
+#include <algorithm>
+
+#include "PcmVolumeControl.h"
 
 PcmPlayer::PcmPlayer()
 {
-    mCond = new Cond();
+
 }
 
 PcmPlayer::~PcmPlayer()
@@ -23,6 +25,9 @@ bool PcmPlayer::startPlay()
 
     bool is_succeed = openDevice();
     m_device_opened = is_succeed;
+
+    m_cache_size = 0.15 * m_sample_rate * m_channel; //计算150ms的缓存大小
+
     return is_succeed;
 }
 
@@ -33,27 +38,24 @@ bool PcmPlayer::stopPlay()
     return isSucceed;
 }
 
-int PcmPlayer::inputPCMFrame(PCMFramePtr framePtr)
+int PcmPlayer::inputPCMFrame(PCMFramePtr frame)
 {
     int frame_size = 0;
 
-    if (m_device_opened)
+    if (m_device_opened) //音频设备打开的情况下才处理播放
     {
-        //音频设备打开的情况下才处理播放
-
-        mCond->Lock();
-        mPcmFrameList.push_back(framePtr);
-        frame_size = mPcmFrameList.size();
-        mCond->Unlock();
-        mCond->Signal();
+        std::lock_guard<std::mutex> lck(m_mutex_audio);
+        m_pcm_frame_list.push_back(frame);
+        frame_size = m_pcm_frame_list.size();
+        m_cond_audio.notify_all();
 
     //    qDebug()<<m_sample_rate<<m_channel<<m_device_opened<<framePtr->sampleRate()<<framePtr->channels();
 
-        int channels = framePtr->channels();
-        int sample_rate = framePtr->sampleRate();
+        int channels = frame->channels();
+        int sample_rate = frame->sampleRate();
 
         ///用于实现 播放队列太大的时候,提高播放采样率,用于直播消延时
-        static int use_sample_rate = framePtr->sampleRate();
+        static int use_sample_rate = frame->sampleRate();
         if (frame_size > 20)
         {
         //    use_sample_rate = 32000;
@@ -83,6 +85,7 @@ int PcmPlayer::inputPCMFrame(PCMFramePtr framePtr)
         if ((tick - m_last_try_open_device_time) > 3000)
         {
             //音频设备未打开,则每隔3秒尝试打开一次
+            fprintf(stderr, "try to open audio device ... \n");
             stopPlay();
             startPlay();
         }
@@ -92,44 +95,71 @@ int PcmPlayer::inputPCMFrame(PCMFramePtr framePtr)
 
 int PcmPlayer::getPcmFrameSize()
 {
-//    mCond->Lock();
-    int size = mPcmFrameList.size();
-//    mCond->Unlock();
-
+    int size = m_pcm_frame_list.size();
+// printf("%s:%d size=%d \n", __FILE__, __LINE__, size);
     return size;
 }
 
+// bool PcmPlayer::isFrameFull()
+// {
+//     return (m_ring_buffer->GetValidSize() > m_cache_size);
+// }
+
+void PcmPlayer::clearFrame()
+{
+    std::lock_guard<std::mutex> lck(m_mutex_audio);
+    m_pcm_frame_list.clear();
+}
+
 void PcmPlayer::playAudioBuffer(void *stream, int len)
 {
-    PCMFramePtr pcmFramePtr = nullptr;
 //fprintf(stderr, "%s %d %d \n", __FUNCTION__, len, mPcmFrameList.size());
-    mCond->Lock();
-    if (!mPcmFrameList.empty())
+
+    while (m_last_frame_buffer_size < len)
     {
-        pcmFramePtr = mPcmFrameList.front();
-        mPcmFrameList.pop_front();
+        std::unique_lock<std::mutex> lck(m_mutex_audio);
+
+        while (m_pcm_frame_list.empty())
+        {
+            if (m_cond_audio.wait_for(lck, std::chrono::milliseconds (500)) == std::cv_status::timeout)
+            {
+                break;
+            }
+        }
+
+        if (m_pcm_frame_list.empty())
+        {
+            break;
+        }
+
+        PCMFramePtr pcm_frame = m_pcm_frame_list.front();
+        m_pcm_frame_list.pop_front();
+
+        memcpy(m_last_frame_buffer + m_last_frame_buffer_size, pcm_frame->getBuffer(), pcm_frame->getSize());
+        m_last_frame_buffer_size += pcm_frame->getSize();
+
+        m_current_pts = pcm_frame->pts();
     }
-    mCond->Unlock();
 
-    if (pcmFramePtr != nullptr)
+    if (m_last_frame_buffer_size > 0)
     {
-        /// 这里我的PCM数据都是AV_SAMPLE_FMT_S16 44100 双声道的,且采样都是1024,因此pcmFramePtr->getSize()和len值相等都为4096.
-        /// 所以这里直接拷贝过去就好了。
 //        fprintf(stderr, "%s %d %d \n", __FUNCTION__, pcmFramePtr->getSize(), len);
-
+        int buffer_size = std::min(m_last_frame_buffer_size, len);
         if (m_is_mute)// || mIsNeedPause) //静音 或者 是在暂停的时候跳转了
         {
-            memset(stream, 0x0, pcmFramePtr->getSize());
+            memset(stream, 0x0, len);
         }
         else
         {
-            PcmVolumeControl::RaiseVolume((char*)pcmFramePtr->getBuffer(), pcmFramePtr->getSize(), 1, m_volume);
-            memcpy(stream, (uint8_t *)pcmFramePtr->getBuffer(), pcmFramePtr->getSize());
+            PcmVolumeControl::RaiseVolume((char*)m_last_frame_buffer, buffer_size, 1, m_volume);
+            memcpy(stream, m_last_frame_buffer, buffer_size);
         }
 
-        len -= pcmFramePtr->getSize();
-
-        m_current_pts = pcmFramePtr->pts();
+        m_last_frame_buffer_size -= buffer_size;
+        if (m_last_frame_buffer_size > 0)
+        {
+            memmove(m_last_frame_buffer, m_last_frame_buffer+buffer_size, m_last_frame_buffer_size);
+        }
     }
 
 }

+ 12 - 4
module/VideoPlayer/src/PcmPlayer/PcmPlayer.h

@@ -3,8 +3,8 @@
 
 #include <thread>
 #include <list>
+#include <mutex>
 
-#include "Mutex/Cond.h"
 #include "frame/AudioFrame/PCMFrame.h"
 
 struct AudioDevice
@@ -24,8 +24,10 @@ public:
     bool startPlay();
     bool stopPlay();
 
-    int inputPCMFrame(PCMFramePtr framePtr);
+    int inputPCMFrame(PCMFramePtr frame);
     int getPcmFrameSize();
+    bool isFrameFull(); //缓存是否满了
+    void clearFrame();
 
     uint32_t getCurrentPts(){return m_current_pts;}
 
@@ -36,14 +38,20 @@ public:
     bool deviceOpened(){return m_device_opened;}
 
 protected:
-    Cond *mCond;
-    std::list<PCMFramePtr> mPcmFrameList;
+    std::mutex m_mutex_audio;
+    std::condition_variable m_cond_audio;
+    std::list<PCMFramePtr> m_pcm_frame_list;
+    
+    /// 用于存放上一次未处理完的数据
+    uint8_t m_last_frame_buffer[10240];
+    int m_last_frame_buffer_size = 0;
 
     uint32_t m_current_pts = 0; //当前播放帧的时间戳
     bool m_device_opened = false; //设备是否已经打开了
     uint64_t m_last_try_open_device_time = 0; //上一次尝试打开音频设备的时间
     int m_sample_rate = 0;
     int m_channel = 0;
+    int m_cache_size = 81920; //缓存大小
 
     ///音量相关变量
     bool  m_is_mute = false;

+ 120 - 79
module/VideoPlayer/src/VideoPlayer/VideoPlayer.cpp

@@ -9,26 +9,29 @@
 #include "PcmPlayer/PcmPlayer_SDL.h"
 
 #include <stdio.h>
-
+#include <iostream>
+#include <QDebug>
 VideoPlayer::VideoPlayer()
 {
-    mConditon_Video = new Cond;
-    mConditon_Audio = new Cond;
-
-    mPlayerState = VideoPlayer_Stop;
+    m_state = VideoPlayer::Stop;
 
-    mVideoPlayerCallBack = nullptr;
-
-//    mAudioID = 0;
     mIsMute = false;
 
     mIsNeedPause = false;
 
     mVolume = 1;
 
-    mPcmPlayer = new PcmPlayer_SDL();
+    m_pcm_player = new PcmPlayer_SDL();
 
     this->setSingleMode(true);
+
+    m_thread_video = new Thread();
+    m_thread_video->setSingleMode(true);
+    m_thread_video->setThreadFunc(std::bind(&VideoPlayer::decodeVideoThread, this));
+
+    m_thread_audio = new Thread();
+    m_thread_audio->setSingleMode(true);
+    m_thread_audio->setThreadFunc(std::bind(&VideoPlayer::decodeAudioThread, this));
 }
 
 VideoPlayer::~VideoPlayer()
@@ -60,7 +63,7 @@ bool VideoPlayer::initPlayer()
 
 bool VideoPlayer::startPlay(const std::string &filePath)
 {
-    if (mPlayerState != VideoPlayer_Stop)
+    if (m_state != VideoPlayer::Stop)
     {
         return false;
     }
@@ -69,14 +72,11 @@ bool VideoPlayer::startPlay(const std::string &filePath)
     mIsPause = false;
 
     if (!filePath.empty())
-        mFilePath = filePath;
+    {
+        m_file_path = filePath;
+    }
 
     //启动新的线程实现读取视频文件
-//    std::thread([&](VideoPlayer *pointer)
-//    {
-//        pointer->readVideoFile();
-
-//    }, this).detach();
     this->start();
 
     return true;
@@ -87,7 +87,7 @@ bool VideoPlayer::replay(bool isWait)
 {
     stop(isWait);
 
-    startPlay(mFilePath);
+    startPlay(m_file_path);
 
     return true;
 }
@@ -97,7 +97,7 @@ bool VideoPlayer::play()
     mIsNeedPause = false;
     mIsPause = false;
 
-    if (mPlayerState != VideoPlayer_Pause)
+    if (m_state != VideoPlayer::Pause)
     {
         return false;
     }
@@ -105,8 +105,8 @@ bool VideoPlayer::play()
     uint64_t pauseTime = av_gettime() - mVideoStartTime; //暂停了多长时间
     mVideoStartTime += pauseTime; //将暂停的时间加到开始播放的时间上,保证同步不受暂停的影响
 
-    mPlayerState = VideoPlayer_Playing;
-    doPlayerStateChanged(VideoPlayer_Playing, mVideoStream != nullptr, mAudioStream != nullptr);
+    m_state = VideoPlayer::Playing;
+    doPlayerStateChanged(VideoPlayer::Playing, mVideoStream != nullptr, mAudioStream != nullptr);
 
     return true;
 }
@@ -117,30 +117,34 @@ bool VideoPlayer::pause()
 
     mIsPause = true;
 
-    if (mPlayerState != VideoPlayer_Playing)
+    if (m_state != VideoPlayer::Playing)
     {
         return false;
     }
 
     mPauseStartTime = av_gettime();
 
-    mPlayerState = VideoPlayer_Pause;
+    m_state = VideoPlayer::Pause;
 
-    emit doPlayerStateChanged(VideoPlayer_Pause, mVideoStream != nullptr, mAudioStream != nullptr);
+    emit doPlayerStateChanged(VideoPlayer::Pause, mVideoStream != nullptr, mAudioStream != nullptr);
 
     return true;
 }
 
 bool VideoPlayer::stop(bool isWait)
 {
-    if (mPlayerState == VideoPlayer_Stop)
+    if (m_state == VideoPlayer::Stop)
     {
         return false;
     }
 
-    mPlayerState = VideoPlayer_Stop;
+    m_state = VideoPlayer::Stop;
     mIsQuit = true;
 
+    ///唤醒等待中的线程
+    m_cond_video.notify_all();
+    m_cond_audio.notify_all();
+
     if (isWait)
     {
         while(!mIsReadThreadFinished)
@@ -165,13 +169,13 @@ void VideoPlayer::seek(int64_t pos)
 void VideoPlayer::setMute(bool isMute)
 {
     mIsMute = isMute;
-    mPcmPlayer->setMute(isMute);
+    m_pcm_player->setMute(isMute);
 }
 
 void VideoPlayer::setVolume(float value)
 {
     mVolume = value;
-    mPcmPlayer->setVolume(value);
+    m_pcm_player->setVolume(value);
 }
 
 double VideoPlayer::getCurrentTime()
@@ -279,7 +283,7 @@ void VideoPlayer::run()
     mIsReadFinished = false;
     mIsReadError = false;
 
-    const char * file_path = mFilePath.c_str();
+    const char * file_path = m_file_path.c_str();
 
     pFormatCtx = nullptr;
     pCodecCtx = nullptr;
@@ -375,12 +379,8 @@ void VideoPlayer::run()
 
         mVideoStream = video_stream;
 
-        ///创建一个线程专门用来解码视频
-        std::thread([&](VideoPlayer *pointer)
-        {
-            pointer->decodeVideoThread();
-
-        }, this).detach();
+        ///启动视频解码线程
+        m_thread_video->start();
 
     }
 
@@ -502,15 +502,35 @@ void VideoPlayer::run()
 //            }
         }
 
+        ///启动音频解码线程
+        m_thread_audio->start();
     }
 
     av_dump_format(pFormatCtx, 0, file_path, 0); //输出视频信息
 
-    mPlayerState = VideoPlayer_Playing;
-    doPlayerStateChanged(VideoPlayer_Playing, mVideoStream != nullptr, mAudioStream != nullptr);
+    m_state = VideoPlayer::Playing;
+    doPlayerStateChanged(VideoPlayer::Playing, mVideoStream != nullptr, mAudioStream != nullptr);
 
     mVideoStartTime = av_gettime();
-//fprintf(stderr, "%s mIsQuit=%d mIsPause=%d file_path=%s \n", __FUNCTION__, mIsQuit, mIsPause, file_path);
+fprintf(stderr, "%s mIsQuit=%d mIsPause=%d file_path=%s \n", __FUNCTION__, mIsQuit, mIsPause, file_path);
+
+    if (m_file_path.find("rtmp://") != std::string::npos
+        || m_file_path.find("rtsp://") != std::string::npos) 
+    {
+        m_is_live_mode = true;
+    }
+    else
+    {
+        m_is_live_mode = false;
+    }
+
+    video_clock = 0;
+    audio_clock = 0;
+    seek_req = 0;
+    seek_time = 0;
+    seek_flag_audio = 0;
+    seek_flag_video = 0;
+
     while (1)
     {
         if (mIsQuit)
@@ -534,12 +554,35 @@ void VideoPlayer::run()
             {
                 seek_target = av_rescale_q(seek_target, aVRational, pFormatCtx->streams[stream_index]->time_base);
             }
+std::cout<<" video:"<<pFormatCtx->streams[videoStream]->duration<<" "<<pFormatCtx->streams[videoStream]->time_base.den
+         <<" audio:"<<pFormatCtx->streams[audioStream]->duration<<" "<<pFormatCtx->streams[audioStream]->time_base.den<<std::endl;
 
+            bool seek_succeed = false;
             if (av_seek_frame(pFormatCtx, stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0)
             {
-                fprintf(stderr, "%s: error while seeking\n", file_path);
+                fprintf(stderr, "%s: error while seeking. stream_index=%d \n", file_path, stream_index);
+                if (audioStream >= 0 && stream_index != audioStream)
+                {
+                    stream_index = audioStream;
+                    seek_target = av_rescale_q(seek_target, aVRational, pFormatCtx->streams[stream_index]->time_base);
+                    if (av_seek_frame(pFormatCtx, stream_index, seek_target, AVSEEK_FLAG_ANY) < 0)
+                    {
+                        fprintf(stderr, "%s: error while seeking. stream_index=%d \n", file_path, stream_index);
+                    }
+                    else
+                    {
+                        seek_succeed = true;
+                        fprintf(stderr, "%s: seeking success. stream_index=%d \n", file_path, stream_index);
+                    }
+                }
             }
             else
+            {
+                seek_succeed = true;
+                fprintf(stderr, "%s: seeking success. stream_index=%d \n", file_path, stream_index);
+            }
+
+            if (seek_succeed)
             {
                 if (audioStream >= 0)
                 {
@@ -578,7 +621,8 @@ void VideoPlayer::run()
 
         //这里做了个限制  当队列里面的数据超过某个大小的时候 就暂停读取  防止一下子就把视频读完了,导致的空间分配不足
         //这个值可以稍微写大一些
-        if (mAudioPacktList.size() > MAX_AUDIO_SIZE || mVideoPacktList.size() > MAX_VIDEO_SIZE)
+// fprintf(stderr, "%s %d m_audio_pkt_list.size()=%d m_video_pkt_list.size()=%d \n", __FILE__, __LINE__, m_audio_pkt_list.size(), m_video_pkt_list.size());
+        if (m_audio_pkt_list.size() >= MAX_AUDIO_SIZE || m_video_pkt_list.size() >= MAX_VIDEO_SIZE)
         {
             mSleep(10);
             continue;
@@ -595,12 +639,12 @@ void VideoPlayer::run()
 
         mCallStartTime = av_gettime();
         mIsOpenStream  = false;
-
+// qDebug()<<__FUNCTION__<<video_clock<<audio_clock;
         if (av_read_frame(pFormatCtx, &packet) < 0)
         {
             mIsReadFinished = true;
             mIsReadError = true;
-// qDebug("%s av_read_frame failed \n", __FUNCTION__);
+qDebug("%s av_read_frame failed \n", __FUNCTION__);
 //            if (mIsQuit)
 //            {
 //                break; //解码线程也执行完了 可以退出了
@@ -609,7 +653,8 @@ void VideoPlayer::run()
             mSleep(10);
             continue;
         }
-//qDebug("%s mIsQuit=%d mIsPause=%d packet.stream_index=%d \n", __FUNCTION__, mIsQuit, mIsPause, packet.stream_index);
+// qDebug("%s mIsQuit=%d mIsPause=%d packet.stream_index=%d \n", __FUNCTION__, mIsQuit, mIsPause, packet.stream_index);
+// fprintf(stderr, "%s mIsQuit=%d mIsPause=%d packet.stream_index=%d \n", __FUNCTION__, mIsQuit, mIsPause, packet.stream_index);
         if (packet.stream_index == videoStream)
         {
             inputVideoQuene(packet);
@@ -625,9 +670,6 @@ void VideoPlayer::run()
             {
                 inputAudioQuene(packet);
                 //这里我们将数据存入队列 因此不调用 av_free_packet 释放
-
-                //音频解码不开线程,因此这里直接调用解码操作
-                decodeAudioFrame(false);
             }
 
         }
@@ -636,6 +678,7 @@ void VideoPlayer::run()
             // Free the packet that was allocated by av_read_frame
             av_packet_unref(&packet);
         }
+// fprintf(stderr, "%s:%d \n", __FILE__, __LINE__);
     }
 
     ///文件读取结束 跳出循环的情况
@@ -650,20 +693,22 @@ end:
     clearAudioQuene();
     clearVideoQuene();
 
-    if (mPlayerState != VideoPlayer_Stop) //不是外部调用的stop 是正常播放结束
+    if (m_state != VideoPlayer::Stop) //不是外部调用的stop 是正常播放结束
     {
         stop(false);
     }
 
-    mIsAudioThreadFinished = true;
+    ///唤醒等待中的线程
+    m_cond_video.notify_all();
+    m_cond_audio.notify_all();
     while((mVideoStream != nullptr && !mIsVideoThreadFinished) || (mAudioStream != nullptr && !mIsAudioThreadFinished))
     {
 fprintf(stderr, "%s:%d mIsVideoThreadFinished=%d mIsAudioThreadFinished=%d \n", __FILE__, __LINE__, mIsVideoThreadFinished, mIsAudioThreadFinished);
         mSleep(10);
     } //确保视频线程结束后 再销毁队列
 
-//    closeSDL();
-    mPcmPlayer->stopPlay();
+    m_pcm_player->stopPlay();
+    m_pcm_player->clearFrame();
 
     if (swrCtx != nullptr)
     {
@@ -702,11 +747,11 @@ fprintf(stderr, "%s:%d mIsVideoThreadFinished=%d mIsAudioThreadFinished=%d \n",
 
     if (mIsReadError && !mIsQuit)
     {
-        doPlayerStateChanged(VideoPlayer_ReadError, mVideoStream != nullptr, mAudioStream != nullptr);
+        doPlayerStateChanged(VideoPlayer::ReadError, mVideoStream != nullptr, mAudioStream != nullptr);
     }
     else
     {
-        doPlayerStateChanged(VideoPlayer_Stop, mVideoStream != nullptr, mAudioStream != nullptr);
+        doPlayerStateChanged(VideoPlayer::Stop, mVideoStream != nullptr, mAudioStream != nullptr);
     }
 
     mIsReadThreadFinished = true;
@@ -721,24 +766,22 @@ bool VideoPlayer::inputVideoQuene(const AVPacket &pkt)
 //        return false;
 //    }
 
-    mConditon_Video->Lock();
-    mVideoPacktList.push_back(pkt);
-    mConditon_Video->Signal();
-    mConditon_Video->Unlock();
+    std::lock_guard<std::mutex> lck(m_mutex_video);
+    m_video_pkt_list.push_back(pkt);
+    m_cond_video.notify_all();
 
     return true;
 }
 
 void VideoPlayer::clearVideoQuene()
 {
-    mConditon_Video->Lock();
-    for (AVPacket pkt : mVideoPacktList)
+    std::lock_guard<std::mutex> lck(m_mutex_video);
+    for (AVPacket pkt : m_video_pkt_list)
     {
 //        av_free_packet(&pkt);
         av_packet_unref(&pkt);
     }
-    mVideoPacktList.clear();
-    mConditon_Video->Unlock();
+    m_video_pkt_list.clear();
 }
 
 bool VideoPlayer::inputAudioQuene(const AVPacket &pkt)
@@ -747,25 +790,23 @@ bool VideoPlayer::inputAudioQuene(const AVPacket &pkt)
 //    {
 //        return false;
 //    }
-
-    mConditon_Audio->Lock();
-    mAudioPacktList.push_back(pkt);
-    mConditon_Audio->Signal();
-    mConditon_Audio->Unlock();
+    std::lock_guard<std::mutex> lck(m_mutex_audio);
+    m_audio_pkt_list.push_back(pkt);
+    m_cond_audio.notify_all();
 
     return true;
 }
 
 void VideoPlayer::clearAudioQuene()
 {
-    mConditon_Audio->Lock();
-    for (AVPacket pkt : mAudioPacktList)
+    std::lock_guard<std::mutex> lck(m_mutex_audio);
+    for (AVPacket pkt : m_audio_pkt_list)
     {
 //        av_free_packet(&pkt);
         av_packet_unref(&pkt);
     }
-    mAudioPacktList.clear();
-    mConditon_Audio->Unlock();
+    m_audio_pkt_list.clear();
+    m_pcm_player->clearFrame();
 }
 
 ///当使用界面类继承了本类之后,以下函数不会执行
@@ -775,9 +816,9 @@ void VideoPlayer::doOpenVideoFileFailed(const int &code)
 {
     fprintf(stderr, "%s \n", __FUNCTION__);
 
-    if (mVideoPlayerCallBack != nullptr)
+    if (m_event_handle != nullptr)
     {
-        mVideoPlayerCallBack->onOpenVideoFileFailed(code);
+        m_event_handle->onOpenVideoFileFailed(code);
     }
 
 }
@@ -787,9 +828,9 @@ void VideoPlayer::doOpenSdlFailed(const int &code)
 {
     fprintf(stderr, "%s \n", __FUNCTION__);
 
-    if (mVideoPlayerCallBack != nullptr)
+    if (m_event_handle != nullptr)
     {
-        mVideoPlayerCallBack->onOpenSdlFailed(code);
+        m_event_handle->onOpenSdlFailed(code);
     }
 }
 
@@ -798,20 +839,20 @@ void VideoPlayer::doTotalTimeChanged(const int64_t &uSec)
 {
     fprintf(stderr, "%s \n", __FUNCTION__);
 
-    if (mVideoPlayerCallBack != nullptr)
+    if (m_event_handle != nullptr)
     {
-        mVideoPlayerCallBack->onTotalTimeChanged(uSec);
+        m_event_handle->onTotalTimeChanged(uSec);
     }
 }
 
 ///播放器状态改变的时候回调此函数
-void VideoPlayer::doPlayerStateChanged(const VideoPlayerState &state, const bool &hasVideo, const bool &hasAudio)
+void VideoPlayer::doPlayerStateChanged(const VideoPlayer::State &state, const bool &hasVideo, const bool &hasAudio)
 {
     fprintf(stderr, "%s state=%d\n", __FUNCTION__, state);
 
-    if (mVideoPlayerCallBack != nullptr)
+    if (m_event_handle != nullptr)
     {
-        mVideoPlayerCallBack->onPlayerStateChanged(state, hasVideo, hasAudio);
+        m_event_handle->onPlayerStateChanged(state, hasVideo, hasAudio);
     }
 
 }
@@ -820,7 +861,7 @@ void VideoPlayer::doPlayerStateChanged(const VideoPlayerState &state, const bool
 void VideoPlayer::doDisplayVideo(const uint8_t *yuv420Buffer, const int &width, const int &height)
 {
 //    fprintf(stderr, "%s width=%d height=%d \n", __FUNCTION__, width, height);
-    if (mVideoPlayerCallBack != nullptr)
+    if (m_event_handle != nullptr)
     {
         VideoFramePtr videoFrame = std::make_shared<VideoFrame>();
 
@@ -829,6 +870,6 @@ void VideoPlayer::doDisplayVideo(const uint8_t *yuv420Buffer, const int &width,
         ptr->initBuffer(width, height);
         ptr->setYUVbuf(yuv420Buffer);
 
-        mVideoPlayerCallBack->onDisplayVideo(videoFrame);
+        m_event_handle->onDisplayVideo(videoFrame);
     }
 }

+ 48 - 14
module/VideoPlayer/src/VideoPlayer/VideoPlayer.h

@@ -40,10 +40,9 @@ extern "C"
 #define CONFIG_AVFILTER 1
 
 #include "types.h"
-#include "Mutex/Cond.h"
-#include "EventHandle/VideoPlayerEventHandle.h"
 #include "PcmPlayer/PcmPlayer.h"
 #include "util/thread.h"
+#include "frame/VideoFrame/VideoFrame.h"
 
 #define SDL_AUDIO_BUFFER_SIZE 1024
 #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
@@ -61,6 +60,34 @@ extern "C"
 
 class VideoPlayer : public Thread
 {
+public:
+    enum State
+    {
+        Playing = 0,
+        Pause,
+        Stop,
+        ReadError,
+    };
+
+    class EventHandle
+    {
+    public:
+        ///打开文件失败
+        virtual void onOpenVideoFileFailed(const int &code = 0) = 0;
+
+        ///打开sdl失败的时候回调此函数
+        virtual void onOpenSdlFailed(const int &code) = 0;
+
+        ///获取到视频时长的时候调用此函数
+        virtual void onTotalTimeChanged(const int64_t &uSec) = 0;
+
+        ///播放器状态改变的时候回调此函数
+        virtual void onPlayerStateChanged(const VideoPlayer::State &state, const bool &hasVideo, const bool &hasAudio) = 0;
+
+        ///播放视频,此函数不宜做耗时操作,否则会影响播放的流畅性。
+        virtual void onDisplayVideo(VideoFramePtr videoFrame) = 0;
+    };
+
 public:
     VideoPlayer();
     ~VideoPlayer();
@@ -72,7 +99,7 @@ public:
      * @brief setVideoPlayerCallBack 设置播放器回调函数
      * @param pointer
      */
-    void setVideoPlayerCallBack(VideoPlayerCallBack *pointer){mVideoPlayerCallBack=pointer;}
+    void setEventHandle(VideoPlayer::EventHandle *handle){m_event_handle=handle;}
 
     bool startPlay(const std::string &filePath);
 
@@ -97,16 +124,18 @@ public:
 
 protected:
     void run(); //读取视频文件
-    void decodeVideoThread();
+    void decodeVideoThread(); //解码视频的线程
+    void decodeAudioThread(); //解码音频的线程
 
 //    static void sdlAudioCallBackFunc(void *userdata, Uint8 *stream, int len);
 //    void sdlAudioCallBack(Uint8 *stream, int len);
-    int decodeAudioFrame(bool isBlock = false);
+    // int decodeAudioFrame(bool isBlock = false);
 
 private:
-    std::string mFilePath; //视频文件路径
+    std::string m_file_path; //视频文件路径
+    bool m_is_live_mode = false; //是否为直播流
 
-    VideoPlayerState mPlayerState; //播放状态
+    State m_state; //播放状态
 
     ///音量相关变量
     bool  mIsMute;
@@ -182,23 +211,28 @@ private:
 #endif
 
     ///视频帧队列
-    Cond *mConditon_Video;
-    std::list<AVPacket> mVideoPacktList;
+    Thread *m_thread_video = nullptr;
+    std::mutex m_mutex_video;
+    std::condition_variable m_cond_video;
+    std::list<AVPacket> m_video_pkt_list;
     bool inputVideoQuene(const AVPacket &pkt);
     void clearVideoQuene();
 
     ///音频帧队列
-    Cond *mConditon_Audio;
-    std::list<AVPacket> mAudioPacktList;
+    Thread *m_thread_audio = nullptr;
+    std::mutex m_mutex_audio;
+    std::condition_variable m_cond_audio;
+    std::list<AVPacket> m_audio_pkt_list;
     bool inputAudioQuene(const AVPacket &pkt);
     void clearAudioQuene();
+    
 
 //    ///本播放器中SDL仅用于播放音频,不用做别的用途
 //    ///SDL播放音频相关
 //    SDL_AudioDeviceID mAudioID;
 //    int openSDL();
 //    void closeSDL();
-    PcmPlayer *mPcmPlayer = nullptr;
+    PcmPlayer *m_pcm_player = nullptr;
 
     int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph, AVFilterContext *source_ctx, AVFilterContext *sink_ctx);
     int configure_video_filters(AVFilterGraph *graph, const char *vfilters, AVFrame *frame);
@@ -206,7 +240,7 @@ private:
     ///回调函数相关,主要用于输出信息给界面
 private:
     ///回调函数
-    VideoPlayerCallBack *mVideoPlayerCallBack;
+    EventHandle *m_event_handle = nullptr;
 
     ///打开文件失败
     void doOpenVideoFileFailed(const int &code = 0);
@@ -218,7 +252,7 @@ private:
     void doTotalTimeChanged(const int64_t &uSec);
 
     ///播放器状态改变的时候回调此函数
-    void doPlayerStateChanged(const VideoPlayerState &state, const bool &hasVideo, const bool &hasAudio);
+    void doPlayerStateChanged(const VideoPlayer::State &state, const bool &hasVideo, const bool &hasAudio);
 
     ///显示视频数据,此函数不宜做耗时操作,否则会影响播放的流畅性。
     void doDisplayVideo(const uint8_t *yuv420Buffer, const int &width, const int &height);

+ 229 - 100
module/VideoPlayer/src/VideoPlayer/VideoPlayer_AudioThread.cpp

@@ -10,115 +10,45 @@
 
 #include <stdio.h>
 
-//void VideoPlayer::sdlAudioCallBackFunc(void *userdata, Uint8 *stream, int len)
-//{
-//    VideoPlayer *player = (VideoPlayer*)userdata;
-//    player->sdlAudioCallBack(stream, len);
-//}
-
-//void VideoPlayer::sdlAudioCallBack(Uint8 *stream, int len)
-//{
-//    int len1, audio_data_size;
-////fprintf(stderr, "len=%d \n", len);
-//    /*   len是由SDL传入的SDL缓冲区的大小,如果这个缓冲未满,我们就一直往里填充数据 */
-//    while (len > 0)
-//    {
-//        /*  audio_buf_index 和 audio_buf_size 标示我们自己用来放置解码出来的数据的缓冲区,*/
-//        /*   这些数据待copy到SDL缓冲区, 当audio_buf_index >= audio_buf_size的时候意味着我*/
-//        /*   们的缓冲为空,没有数据可供copy,这时候需要调用audio_decode_frame来解码出更
-//         /*   多的桢数据 */
-//        if (audio_buf_index >= audio_buf_size)
-//        {
-//            audio_data_size = decodeAudioFrame();
-
-//            /* audio_data_size < 0 标示没能解码出数据,我们默认播放静音 */
-//            if (audio_data_size <= 0)
-//            {
-//                /* silence */
-//                audio_buf_size = 1024;
-//                /* 清零,静音 */
-//                memset(audio_buf, 0, audio_buf_size);
-//            }
-//            else
-//            {
-//                audio_buf_size = audio_data_size;
-//            }
-//            audio_buf_index = 0;
-//        }
-//        /*  查看stream可用空间,决定一次copy多少数据,剩下的下次继续copy */
-//        len1 = audio_buf_size - audio_buf_index;
-
-//        if (len1 > len)
-//        {
-//            len1 = len;
-//        }
-
-//        if (audio_buf == NULL) return;
-
-//        if (mIsMute || mIsNeedPause) //静音 或者 是在暂停的时候跳转了
-//        {
-//            memset(audio_buf + audio_buf_index, 0, len1);
-//        }
-//        else
-//        {
-//            PcmVolumeControl::RaiseVolume((char*)audio_buf + audio_buf_index, len1, 1, mVolume);
-//        }
-
-//        memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1);
-
-////        SDL_memset(stream, 0x0, len);// make sure this is silence.
-////        SDL_MixAudio(stream, (uint8_t *) audio_buf + audio_buf_index, len1, SDL_MIX_MAXVOLUME);
-
-////        SDL_MixAudio(stream, (uint8_t * )is->audio_buf + is->audio_buf_index, len1, 50);
-////        SDL_MixAudioFormat(stream, (uint8_t * )is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, 50);
-
-//        len -= len1;
-//        stream += len1;
-//        audio_buf_index += len1;
-
-//    }
-
-//}
-
-int VideoPlayer::decodeAudioFrame(bool isBlock)
+void VideoPlayer::decodeAudioThread()
 {
-    int audioBufferSize = 0;
+    fprintf(stderr, "%s start \n", __FUNCTION__);
+    mIsAudioThreadFinished = false;
+    
     float pts_s = 0.0f; //时间戳(秒)
 
-    while(1)
+    while (1)
     {
         if (mIsQuit)
         {
-            mIsAudioThreadFinished = true;
             clearAudioQuene(); //清空队列
             break;
         }
 
         if (mIsPause == true) //判断暂停
         {
-            break;
+            mSleep(10);
+            continue;
         }
 
-        mConditon_Audio->Lock();
-int audio_list_size = mAudioPacktList.size();
-//fprintf(stderr, "mAudioPacktList.size()=%d \n", audio_list_size);
-        if (mAudioPacktList.size() <= 0)
+        std::unique_lock<std::mutex> lck(m_mutex_audio);
+        while (!mIsQuit && m_audio_pkt_list.empty())
         {
-            if (isBlock)
-            {
-                mConditon_Audio->Wait();
-            }
-            else
+            m_cond_audio.wait(lck);
+        }
+
+        if (m_audio_pkt_list.empty())
+        {
+            if (mIsReadFinished)
             {
-                mConditon_Audio->Unlock();
                 break;
             }
+            continue;
         }
 
-        AVPacket packet = mAudioPacktList.front();
-        mAudioPacktList.pop_front();
-//qDebug()<<__FUNCTION__<<mAudioPacktList.size();
-        mConditon_Audio->Unlock();
+        AVPacket packet = m_audio_pkt_list.front();
+        m_audio_pkt_list.pop_front();
+        lck.unlock();
 
         AVPacket *pkt = &packet;
 
@@ -149,7 +79,15 @@ int audio_list_size = mAudioPacktList.size();
            }
         }
 
-        int got_frame = 0;
+        ///直播流为了保证降低延迟,当音频播放队列过大时,会提高播放的采样率
+        ///因此,非直播流,不能一次性把所有音频塞入队列,需要限制播放队列中的数据量
+        if (!m_is_live_mode)
+        {
+            while (m_pcm_player->getPcmFrameSize() > 15)
+            {
+                mSleep(5);
+            }
+        }
 
         //解码AVPacket->AVFrame
         if (int ret = avcodec_send_packet(aCodecCtx, &packet) && ret != 0)
@@ -245,28 +183,219 @@ int audio_list_size = mAudioPacktList.size();
                     int resampled_data_size = len2 * audio_tgt_channels * av_get_bytes_per_sample(out_sample_fmt);
                     int OneChannelDataSize = resampled_data_size / audio_tgt_channels;
 
-                    audioBufferSize = resampled_data_size;
-
                     PCMFramePtr pcmFramePtr = std::make_shared<PCMFrame>();
                     pcmFramePtr->setFrameBuffer(audio_buf, resampled_data_size);
                     pcmFramePtr->setFrameInfo(m_out_sample_rate, audio_tgt_channels, pts_s*1000);
 
-                    int audio_frame_size = mPcmPlayer->inputPCMFrame(pcmFramePtr);
+                    int audio_frame_size = m_pcm_player->inputPCMFrame(pcmFramePtr);
 //qDebug()<<resampled_data_size<<audio_frame_size;
-                    audio_clock = mPcmPlayer->getCurrentPts() / 1000.0;
+                    audio_clock = m_pcm_player->getCurrentPts() / 1000.0;
                 }
 
-                got_frame = 1;
             }
         }
 
         av_packet_unref(&packet);
+    }
 
-        if (got_frame)
-        {
-            break;
-        }
+    ///等待播放完成
+    while (m_pcm_player->getPcmFrameSize() > 0)
+    {
+        mSleep(5);
     }
 
-    return audioBufferSize;
+    mIsAudioThreadFinished = true;
+    fprintf(stderr, "%s finished \n", __FUNCTION__);
 }
+
+
+// int VideoPlayer::decodeAudioFrame(bool isBlock)
+// {
+//     int audioBufferSize = 0;
+//     float pts_s = 0.0f; //时间戳(秒)
+
+//     while(1)
+//     {
+//         if (mIsQuit)
+//         {
+//             mIsAudioThreadFinished = true;
+//             clearAudioQuene(); //清空队列
+//             break;
+//         }
+
+//         if (mIsPause == true) //判断暂停
+//         {
+//             break;
+//         }
+
+//         mConditon_Audio->Lock();
+// int audio_list_size = mAudioPacktList.size();
+// //fprintf(stderr, "mAudioPacktList.size()=%d \n", audio_list_size);
+//         // if (mAudioPacktList.size() <= 0)
+//         // {
+//         //     if (isBlock)
+//         //     {
+//         //         mConditon_Audio->Wait();
+//         //     }
+//         //     else
+//         //     {
+//         //         mConditon_Audio->Unlock();
+//         //         break;
+//         //     }
+//         // }
+
+//         AVPacket packet = mAudioPacktList.front();
+//         mAudioPacktList.pop_front();
+// //qDebug()<<__FUNCTION__<<mAudioPacktList.size();
+//         mConditon_Audio->Unlock();
+
+//         AVPacket *pkt = &packet;
+
+//         /* if update, update the audio clock w/pts */
+//         if (pkt->pts != AV_NOPTS_VALUE)
+//         {
+//             pts_s = av_q2d(mAudioStream->time_base) * pkt->pts;
+//         }
+
+//         //收到这个数据 说明刚刚执行过跳转 现在需要把解码器的数据 清除一下
+//         if(strcmp((char*)pkt->data,FLUSH_DATA) == 0)
+//         {
+//             avcodec_flush_buffers(aCodecCtx);
+//             av_packet_unref(pkt);
+//             continue;
+//         }
+
+//         if (seek_flag_audio)
+//         {
+//             //发生了跳转 则跳过关键帧到目的时间的这几帧
+//            if (pts_s < seek_time)
+//            {
+//                continue;
+//            }
+//            else
+//            {
+//                seek_flag_audio = 0;
+//            }
+//         }
+
+//         int got_frame = 0;
+
+//         //解码AVPacket->AVFrame
+//         if (int ret = avcodec_send_packet(aCodecCtx, &packet) && ret != 0)
+//         {
+//            char buffer[1024] = {0};
+//            av_strerror(ret, buffer, 1024);
+//            fprintf(stderr, "input AVPacket to decoder failed! ret = %d %s\n", ret, buffer);
+//         }
+//         else
+//         {
+//             while(1)
+//             {
+//                 int ret = avcodec_receive_frame(aCodecCtx, aFrame);
+//                 if (ret != 0)
+//                 {
+//         //            char buffer[1024] = {0};
+//         //            av_strerror(ret, buffer, 1024);
+//         //            fprintf(stderr, "avcodec_receive_frame = %d %s\n", ret, buffer);
+//                     break;
+//                 }
+
+//                 /* if update, update the audio clock w/pts */
+//                 if (packet.pts != AV_NOPTS_VALUE)
+//                 {
+//                     audio_clock = 1000 * av_q2d(mAudioStream->time_base) * packet.pts;
+//                 }
+
+//                 int out_sample_rate = m_out_sample_rate;
+
+//                 /// ffmpeg解码之后得到的音频数据不是SDL想要的,
+//                 /// 因此这里需要重采样成44100 双声道 AV_SAMPLE_FMT_S16
+
+//                 /// 需要保证重采样后音频的时间是相同的,不同采样率下同样时间采集的数据采样点个数肯定不一样。
+//                 /// 因此就需要重新计算采样点个数(使用下面的函数)
+//                 /// 将in_sample_rate的采样次数换算成out_sample_rate对应的采样次数
+//                 int nb_samples = av_rescale_rnd(swr_get_delay(swrCtx, out_sample_rate) + aFrame->nb_samples, out_sample_rate, m_in_sample_rate, AV_ROUND_UP);
+//     //qDebug()<<swr_get_delay(swrCtx, out_sample_rate) + aFrame->nb_samples<<aFrame->nb_samples<<nb_samples;
+//     //            int nb_samples = av_rescale_rnd(aFrame->nb_samples, out_sample_rate, m_in_sample_rate, AV_ROUND_INF);
+//                 if (aFrame_ReSample != nullptr)
+//                 {
+//                     if (aFrame_ReSample->nb_samples != nb_samples || aFrame_ReSample->sample_rate != out_sample_rate)
+//                     {
+//                         av_frame_free(&aFrame_ReSample);
+//                         aFrame_ReSample = nullptr;
+//                     }
+//                 }
+
+//                 ///解码一帧后才能获取到采样率等信息,因此将初始化放到这里
+//                 if (aFrame_ReSample == nullptr)
+//                 {
+//                     aFrame_ReSample = av_frame_alloc();
+
+//                     aFrame_ReSample->format = out_sample_fmt;
+//                     aFrame_ReSample->channel_layout = out_ch_layout;
+//                     aFrame_ReSample->sample_rate = out_sample_rate;
+//                     aFrame_ReSample->nb_samples = nb_samples;
+
+//                     int ret = av_samples_fill_arrays(aFrame_ReSample->data, aFrame_ReSample->linesize, audio_buf, audio_tgt_channels, aFrame_ReSample->nb_samples, out_sample_fmt, 0);
+//     //                int ret = av_frame_get_buffer(aFrame_ReSample, 0);
+//                     if (ret < 0)
+//                     {
+//                         fprintf(stderr, "Error allocating an audio buffer\n");
+//     //                        exit(1);
+//                     }
+//                 }
+
+//                 ///2024-09-16
+//                 //当重采样的采样率不一致的时候,原先的方法会存在杂音问题,解决方法如下:
+//                 // 1) 如果没有提供足够的空间用于保存输出数据,采样数据会缓存在swr中。可以通过 swr_get_out_samples()来获取下一次调用swr_convert在给定输入样本数量下输出样本数量的上限,来提供足够的空间。
+//                 // 2)如果是采样频率转换,转换完成后采样数据可能会缓存在swr中,它希望你能给它更多的输入数据。
+//                 // 3)如果实际上并不需要更多输入数据,通过调用swr_convert(),其中参数in_count设置为0来获取缓存在swr中的数据。
+//                 // 4)转换结束之后需要冲刷swr_context的缓冲区,通过调用swr_convert(),其中参数in设置为NULL,参数in_count设置为0。
+//                 for(int i=0;i<2;i++)
+//                 {
+//                     ///执行重采样
+//                     int len2;
+
+//                     if (i == 0)
+//                     {
+//                         len2 = swr_convert(swrCtx, aFrame_ReSample->data, aFrame_ReSample->nb_samples, (const uint8_t**)aFrame->data, aFrame->nb_samples);
+//                     }
+//                     else
+//                     {
+//                         len2 = swr_convert(swrCtx, aFrame_ReSample->data, aFrame_ReSample->nb_samples, NULL, 0);
+//                     }
+
+//                     if (len2 <= 0)
+//                     {
+//                         break;
+//                     }
+
+//                     ///必须根据swr_convert实际返回的值计算数据大小
+//                     int resampled_data_size = len2 * audio_tgt_channels * av_get_bytes_per_sample(out_sample_fmt);
+//                     int OneChannelDataSize = resampled_data_size / audio_tgt_channels;
+
+//                     audioBufferSize = resampled_data_size;
+
+//                     PCMFramePtr pcmFramePtr = std::make_shared<PCMFrame>();
+//                     pcmFramePtr->setFrameBuffer(audio_buf, resampled_data_size);
+//                     pcmFramePtr->setFrameInfo(m_out_sample_rate, audio_tgt_channels, pts_s*1000);
+
+//                     int audio_frame_size = m_pcm_player->inputPCMFrame(pcmFramePtr);
+// //qDebug()<<resampled_data_size<<audio_frame_size;
+//                     audio_clock = m_pcm_player->getCurrentPts() / 1000.0;
+//                 }
+
+//                 got_frame = 1;
+//             }
+//         }
+
+//         av_packet_unref(&packet);
+
+//         if (got_frame)
+//         {
+//             break;
+//         }
+//     }
+
+//     return audioBufferSize;
+// }

+ 28 - 31
module/VideoPlayer/src/VideoPlayer/VideoPlayer_VideoThread.cpp

@@ -186,7 +186,7 @@ int VideoPlayer::configure_video_filters(AVFilterGraph *graph, const char *vfilt
     if (autorotate) {
         double theta  = get_rotation(this->mVideoStream);
 //        theta = 90.0f; //测试用
-fprintf(stderr, "%s get_rotation:%d \n", __FUNCTION__, theta);
+// fprintf(stderr, "%s get_rotation:%d \n", __FUNCTION__, theta);
         if (fabs(theta - 90) < 1.0) {
             INSERT_FILT("transpose", "clock");
         } else if (fabs(theta - 180) < 1.0) {
@@ -262,54 +262,51 @@ void VideoPlayer::decodeVideoThread()
             continue;
         }
 
-        mConditon_Video->Lock();
-//fprintf(stderr, "mVideoPacktList.size()=%d \n", mVideoPacktList.size());
-        if (mVideoPacktList.size() <= 0)
+        std::unique_lock<std::mutex> lck(m_mutex_video);
+        while (!mIsQuit && m_video_pkt_list.empty())
+        {
+            m_cond_video.wait(lck);
+        }
+
+        if (m_video_pkt_list.empty())
         {
-            mConditon_Video->Unlock();
             if (mIsReadFinished)
             {
-                //队列里面没有数据了且读取完毕了
                 break;
             }
-            else
-            {
-                mSleep(1); //队列只是暂时没有数据而已
-                continue;
-            }
+            continue;
         }
 
-        AVPacket pkt1 = mVideoPacktList.front();
-        mVideoPacktList.pop_front();
-
-        mConditon_Video->Unlock();
+        AVPacket packet = m_video_pkt_list.front();
+        m_video_pkt_list.pop_front();
+        lck.unlock();
 
-        AVPacket *packet = &pkt1;
+        AVPacket *pkt = &packet;
 
         //收到这个数据 说明刚刚执行过跳转 现在需要把解码器的数据 清除一下
-        if(strcmp((char*)packet->data, FLUSH_DATA) == 0)
+        if(strcmp((char*)pkt->data, FLUSH_DATA) == 0)
         {
             avcodec_flush_buffers(pCodecCtx);
-            av_packet_unref(packet);
+            av_packet_unref(pkt);
             continue;
         }
 
-        if (avcodec_send_packet(pCodecCtx, packet) != 0)
+        if (avcodec_send_packet(pCodecCtx, pkt) != 0)
         {
            qDebug("input AVPacket to decoder failed!\n");
-           av_packet_unref(packet);
+           av_packet_unref(pkt);
            continue;
         }
 
         while (0 == avcodec_receive_frame(pCodecCtx, pFrame))
         {
-            if (packet->dts == AV_NOPTS_VALUE && pFrame->opaque&& *(uint64_t*) pFrame->opaque != AV_NOPTS_VALUE)
+            if (pkt->dts == AV_NOPTS_VALUE && pFrame->opaque&& *(uint64_t*) pFrame->opaque != AV_NOPTS_VALUE)
             {
                 video_pts = *(uint64_t *) pFrame->opaque;
             }
-            else if (packet->dts != AV_NOPTS_VALUE)
+            else if (pkt->dts != AV_NOPTS_VALUE)
             {
-                video_pts = packet->dts;
+                video_pts = pkt->dts;
             }
             else
             {
@@ -324,7 +321,7 @@ void VideoPlayer::decodeVideoThread()
                 //发生了跳转 则跳过关键帧到目的时间的这几帧
                if (video_pts < seek_time)
                {
-                   av_packet_unref(packet);
+                   av_packet_unref(pkt);
                    continue;
                }
                else
@@ -341,9 +338,9 @@ void VideoPlayer::decodeVideoThread()
                     break;
                 }
 
-                if (mAudioStream != NULL && !mIsAudioThreadFinished && mPcmPlayer->deviceOpened())
+                if (mAudioStream != NULL && !mIsAudioThreadFinished && m_pcm_player->deviceOpened())
                 {
-                    if (mIsReadFinished && mAudioPacktList.size() <= 0)
+                    if (mIsReadFinished && m_audio_pkt_list.size() <= 0 && m_pcm_player->getPcmFrameSize() <= 0)
                     {//读取完了 且音频数据也播放完了 就剩下视频数据了  直接显示出来了 不用同步了
                         break;
                     }
@@ -359,7 +356,7 @@ void VideoPlayer::decodeVideoThread()
                     audio_clock = audio_pts;
                 }
 
-    //OUTPUT("%s %f %f \n", __FUNCTION__, video_pts, audio_pts);
+// fprintf(stderr, "%s %f %f \n", __FUNCTION__, video_pts, audio_pts);
                 //主要是 跳转的时候 我们把video_clock设置成0了
                 //因此这里需要更新video_pts
                 //否则当从后面跳转到前面的时候 会卡在这里
@@ -369,7 +366,7 @@ void VideoPlayer::decodeVideoThread()
 
                 int delayTime = (video_pts - audio_pts) * 1000;
 
-                delayTime = delayTime > 5 ? 5:delayTime;
+                delayTime = delayTime > 5 ? 5:delayTime; //最长休眠5ms
 
                 if (!mIsNeedPause)
                 {
@@ -488,8 +485,8 @@ void VideoPlayer::decodeVideoThread()
                     pFrame->linesize, 0, videoHeight, pFrameYUV->data,
                     pFrameYUV->linesize);
 
-//qDebug()<<"(packet->flags & AV_PKT_FLAG_KEY)"<<(packet->flags & AV_PKT_FLAG_KEY);
-            if (!is_key_frame_getted && (packet->flags & AV_PKT_FLAG_KEY)) // is keyframe
+// printf("(packet->flags & AV_PKT_FLAG_KEY) = %d\n", pkt->flags & AV_PKT_FLAG_KEY);
+            if (!is_key_frame_getted && (pkt->flags & AV_PKT_FLAG_KEY)) // is keyframe
             {
                 is_key_frame_getted = true;
             }
@@ -511,7 +508,7 @@ void VideoPlayer::decodeVideoThread()
             }
 
         }
-        av_packet_unref(packet);
+        av_packet_unref(pkt);
     }
 
 #if CONFIG_AVFILTER

+ 0 - 39
module/VideoPlayer/src/frame/AudioFrame/AACFrame.cpp

@@ -1,39 +0,0 @@
-#include "AACFrame.h"
-
-AACFrame::AACFrame()
-{
-    mFrameBuffer = nullptr;
-    mFrameBufferSize = 0;
-}
-
-AACFrame::~AACFrame()
-{
-    if (mFrameBuffer != nullptr)
-    {
-        free(mFrameBuffer);
-
-        mFrameBuffer = nullptr;
-        mFrameBufferSize = 0;
-    }
-}
-
-void AACFrame::setAdtsHeader(const ADTS_HEADER &adts)
-{
-    mAdtsHeader = adts;
-}
-
-void AACFrame::setFrameBuffer(const uint8_t * const buffer, const unsigned int &size)
-{
-    if (mFrameBufferSize < size)
-    {
-        if (mFrameBuffer != nullptr)
-        {
-            free(mFrameBuffer);
-        }
-
-        mFrameBuffer = static_cast<uint8_t*>(malloc(size));
-    }
-
-    memcpy(mFrameBuffer, buffer, size);
-    mFrameBufferSize = size;
-}

+ 0 - 77
module/VideoPlayer/src/frame/AudioFrame/AACFrame.h

@@ -1,77 +0,0 @@
-#ifndef AACFRAME_H
-#define AACFRAME_H
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <memory>
-
-/*
-sampling_frequency_index sampling frequeny [Hz]
-0x0                           96000
-0x1                           88200
-0x2                           64000
-0x3                           48000
-0x4                           44100
-0x5                           32000
-0x6                           24000
-0x7                           22050
-0x8                           16000
-0x9                           2000
-0xa                           11025
-0xb                           8000
-0xc                           reserved
-0xd                           reserved
-0xe                           reserved
-0xf                           reserved
-*/
-typedef struct
-{
-    unsigned int syncword;  //12 bslbf 同步字The bit string ‘1111 1111 1111’,说明一个ADTS帧的开始
-    unsigned int id;        //1 bslbf   MPEG 标示符, 设置为1
-    unsigned int layer;     //2 uimsbf Indicates which layer is used. Set to ‘00’
-    unsigned int protection_absent;  //1 bslbf  表示是否误码校验
-    unsigned int profile;            //2 uimsbf  表示使用哪个级别的AAC,如01 Low Complexity(LC)--- AACLC
-    unsigned int sf_index;           //4 uimsbf  表示使用的采样率下标
-    unsigned int private_bit;        //1 bslbf
-    unsigned int channel_configuration;  //3 uimsbf  表示声道数
-    unsigned int original;               //1 bslbf
-    unsigned int home;                   //1 bslbf
-    /*下面的为改变的参数即每一帧都不同*/
-    unsigned int copyright_identification_bit;   //1 bslbf
-    unsigned int copyright_identification_start; //1 bslbf
-    unsigned int aac_frame_length;               // 13 bslbf  一个ADTS帧的长度包括ADTS头和raw data block
-    unsigned int adts_buffer_fullness;           //11 bslbf     0x7FF 说明是码率可变的码流
-
-    /*no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧.
-    所以说number_of_raw_data_blocks_in_frame == 0
-    表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
-    */
-    unsigned int no_raw_data_blocks_in_frame;    //2 uimsfb
-} ADTS_HEADER;
-
-
-#define AACFramePtr std::shared_ptr<AACFrame>
-
-class AACFrame
-{
-public:
-    AACFrame();
-    ~AACFrame();
-
-    void setAdtsHeader(const ADTS_HEADER &adts);
-    void setFrameBuffer(const uint8_t * const buffer, const unsigned int &size);
-
-    uint8_t *getBuffer(){return mFrameBuffer;}
-    unsigned int getSize(){return  mFrameBufferSize;}
-
-private:
-    ADTS_HEADER mAdtsHeader;
-
-    uint8_t *mFrameBuffer; //aac数据(包括adts头)
-    unsigned int mFrameBufferSize; //aac数据长度(包括adts头的大小)
-
-};
-
-#endif // AACFRAME_H

+ 0 - 8
module/VideoPlayer/src/types.h

@@ -15,14 +15,6 @@
     #include <unistd.h>
 #endif
 
-enum VideoPlayerState
-{
-    VideoPlayer_Playing = 0,
-    VideoPlayer_Pause,
-    VideoPlayer_Stop,
-    VideoPlayer_ReadError,
-};
-
 #if defined(WIN32)
 #else
     void Sleep(long mSeconds);

+ 1 - 1
src/AppConfig.cpp

@@ -37,7 +37,7 @@
 
 QString AppConfig::APPID = "{a1db97ad-b8ed-11e9-a297-0235d2b38928}";
 int AppConfig::VERSION = 1;
-QString AppConfig::VERSION_NAME = "3.0.0";
+QString AppConfig::VERSION_NAME = "2.1.9";
 
 MainWindow *AppConfig::gMainWindow = NULL;
 QRect AppConfig::gMainWindowRect;

+ 1 - 1
src/AppConfig.h

@@ -72,4 +72,4 @@ public:
     static void mSleep(int mSecond);
 };
 
-#endif // APPCONFIG_H
+#endif // APPCONFIG_H

+ 7 - 7
src/MainWindow.cpp

@@ -21,7 +21,7 @@
 #include "Widget/SetVideoUrlDialog.h"
 #include "Widget/mymessagebox_withTitle.h"
 
-Q_DECLARE_METATYPE(VideoPlayerState)
+Q_DECLARE_METATYPE(VideoPlayer::State)
 
 MainWindow::MainWindow(QWidget *parent) :
     DragAbleWidget(parent),
@@ -36,7 +36,7 @@ MainWindow::MainWindow(QWidget *parent) :
 //    setAttribute(Qt::WA_TranslucentBackground);
 
     //因为VideoPlayer::PlayerState是自定义的类型 要跨线程传递需要先注册一下
-    qRegisterMetaType<VideoPlayerState>();
+    qRegisterMetaType<VideoPlayer::State>();
 
     mPopMenu = new QMenu(this);
 
@@ -83,7 +83,7 @@ MainWindow::MainWindow(QWidget *parent) :
     mIsNeedPlayNext = false;
 
     mPlayer = new VideoPlayer();
-    mPlayer->setVideoPlayerCallBack(this);
+    mPlayer->setEventHandle(this);
 
     mTimer = new QTimer; //定时器-获取当前视频时间
     connect(mTimer, &QTimer::timeout, this, &MainWindow::slotTimerTimeOut);
@@ -624,12 +624,12 @@ void MainWindow::onTotalTimeChanged(const int64_t &uSec)
 }
 
 ///播放器状态改变的时候回调此函数
-void MainWindow::onPlayerStateChanged(const VideoPlayerState &state, const bool &hasVideo, const bool &hasAudio)
+void MainWindow::onPlayerStateChanged(const VideoPlayer::State &state, const bool &hasVideo, const bool &hasAudio)
 {
     QMetaObject::invokeMethod(this, [=]()
     {
 qDebug()<<__FUNCTION__<<state<<mIsNeedPlayNext;
-        if (state == VideoPlayer_Stop)
+        if (state == VideoPlayer::Stop)
         {
             ui->stackedWidget->setCurrentWidget(ui->page_open);
 
@@ -650,7 +650,7 @@ qDebug()<<__FUNCTION__<<state<<mIsNeedPlayNext;
 
             mIsNeedPlayNext = true;
         }
-        else if (state == VideoPlayer_Playing)
+        else if (state == VideoPlayer::Playing)
         {
             if (hasVideo)
             {
@@ -668,7 +668,7 @@ qDebug()<<__FUNCTION__<<state<<mIsNeedPlayNext;
 
             mIsNeedPlayNext = true;
         }
-        else if (state == VideoPlayer_Pause)
+        else if (state == VideoPlayer::Pause)
         {
             ui->pushButton_pause->hide();
             ui->pushButton_play->show();

+ 2 - 2
src/MainWindow.h

@@ -27,7 +27,7 @@ class MainWindow;
 }
 
 ///这个是播放器的主界面 包括那些按钮和进度条之类的
-class MainWindow : public DragAbleWidget, public VideoPlayerCallBack
+class MainWindow : public DragAbleWidget, public VideoPlayer::EventHandle
 {
     Q_OBJECT
 
@@ -104,7 +104,7 @@ protected:
     void onTotalTimeChanged(const int64_t &uSec);
 
     ///播放器状态改变的时候回调此函数
-    void onPlayerStateChanged(const VideoPlayerState &state, const bool &hasVideo, const bool &hasAudio);
+    void onPlayerStateChanged(const VideoPlayer::State &state, const bool &hasVideo, const bool &hasAudio);
 
     ///显示视频数据,此函数不宜做耗时操作,否则会影响播放的流畅性。
     void onDisplayVideo(VideoFramePtr videoFrame);