王纲Seek功能

// CGPlayerDemoDlg.h : 头文件
//

#pragma once
#include "CGPlayer-SDL.h"
using namespace ChunGen::Client::Player;

// CCGPlayerDemoDlg 对话框
class CCGPlayerDemoDlg : public CDialogEx
{
// 构造
public:
    CCGPlayerDemoDlg(CWnd* pParent = NULL);    // 标准构造函数

// 对话框数据
    enum { IDD = IDD_CGPLAYERDEMO_DIALOG };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedStartBut();
    afx_msg void OnBnClickedStopBut();
private:
    CGPlayerSdl *cgPlayer;
    bool isPlay;
    HWND handle;
public:
    afx_msg void OnNMReleasedcaptureSlider1(NMHDR *pNMHDR, LRESULT *pResult);
};
CGPlayerDemoDlg.h
// CGPlayerDemoDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "CGPlayerDemo.h"
#include "CGPlayerDemoDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CCGPlayerDemoDlg 对话框



CCGPlayerDemoDlg::CCGPlayerDemoDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(CCGPlayerDemoDlg::IDD, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCGPlayerDemoDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CCGPlayerDemoDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()

    ON_BN_CLICKED(IDC_START_BUT, &CCGPlayerDemoDlg::OnBnClickedStartBut)
    ON_BN_CLICKED(IDC_STOP_BUT, &CCGPlayerDemoDlg::OnBnClickedStopBut)
    ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER1, &CCGPlayerDemoDlg::OnNMReleasedcaptureSlider1)
END_MESSAGE_MAP()


// CCGPlayerDemoDlg 消息处理程序

BOOL CCGPlayerDemoDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO:  在此添加额外的初始化代码
    cgPlayer = nullptr;
    isPlay = false;
    CString str("d://test1.ts");
    //CString str("d://test.mp4");
    GetDlgItem(IDC_URL)->SetWindowText(str);

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CCGPlayerDemoDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CCGPlayerDemoDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCGPlayerDemoDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}





void CCGPlayerDemoDlg::OnBnClickedStartBut()
{
    // TODO:  在此添加控件通知处理程序代码
    if (!isPlay)
    {
        handle = GetDlgItem(IDC_PICTURE)->GetSafeHwnd();
        cgPlayer = new CGPlayerSdl();
        cgPlayer->Init();
        CString  strUrl;
        GetDlgItem(IDC_URL)->GetWindowText(strUrl);
        std::string url = (CStringA)strUrl;
        bool ret = cgPlayer->Open(url);
        if (ret < 0)
        {
            delete cgPlayer;
            cgPlayer = nullptr;
            return;
        }
        cgPlayer->Play(handle);
        isPlay = true;
    }
}


void CCGPlayerDemoDlg::OnBnClickedStopBut()
{
    // TODO:  在此添加控件通知处理程序代码
    if (isPlay)
    {
        if (cgPlayer)
        {
            cgPlayer->Close();
            delete cgPlayer;
            cgPlayer = nullptr;
            isPlay = false;
        }
    }
}


void CCGPlayerDemoDlg::OnNMReleasedcaptureSlider1(NMHDR *pNMHDR, LRESULT *pResult)
{
    // TODO: 在此添加控件通知处理程序代码
    if(isPlay)
    {
        if(cgPlayer) 
        {
            CSliderCtrl   *pSlidCtrl=(CSliderCtrl*)GetDlgItem(IDC_SLIDER1);
            int slidePose = pSlidCtrl->GetPos();
            int min = 0;
            int max = 0;
            pSlidCtrl->GetRange(min, max);
            int slideLength = max - min;    
            int duration = cgPlayer->GetDuration();
            int seekTime = (slidePose + 0.0)/ slideLength * duration;
            cgPlayer->Seek(seekTime);
        }
    }
    *pResult = 0;
}
CGPlayerDemoDlg.cpp
/* Copyright [c] 2018-2028 www.chungen90.com Allrights Reserved*/
#ifndef CG_PLAYER_SDL_H
#define CG_PLAYER_SDL_H
#include <string>
#include <windows.h>


namespace ChunGen{ namespace Client {namespace  Player
{
    class SdlPlayer;
    class  CGPlayerSdl
    {
    public:
        CGPlayerSdl();

        void Init();

        int Open(std::string inputUrl);

        void Play(HWND handle);
        void Seek(int seekTime);
        int GetDuration();
        void Close();
    private:
        SdlPlayer* sdlPlayer;
    };
}}}
#endif
CGPlayer-SDL.h
/* Copyright [c] 2018-2028 www.chungen90.com Allrights Reserved*/
#include "CGPlayer-SDL.h"
#include "SdlPlayer.h"


using namespace ChunGen::Client::Player;

CGPlayerSdl::CGPlayerSdl()
{
     sdlPlayer = nullptr;
}
void CGPlayerSdl::Init()
{
    if(!sdlPlayer)
    {
        sdlPlayer = new SdlPlayer();
        sdlPlayer->Init();
    }
}

int CGPlayerSdl::Open(std::string inputUrl)
{
    int ret  = -1;
    if(sdlPlayer)
    {
        ret = sdlPlayer->OpenInput(inputUrl);
    }
    return ret;
}

void CGPlayerSdl::Play(HWND handle)
{
    if(sdlPlayer)
    {
        sdlPlayer->Play(handle);
    }
}

void  CGPlayerSdl::Seek(int seekTime)
{
    if(sdlPlayer)
    {
        sdlPlayer->Seek(seekTime);
    }
}

int  CGPlayerSdl::GetDuration()
{
    if(sdlPlayer)
    {
        return sdlPlayer->GetDurtion();
    }
    return 0;
}

void CGPlayerSdl::Close()
{
    if(sdlPlayer)
    {
        sdlPlayer->Close();
        delete sdlPlayer;
        sdlPlayer = nullptr;
    }
}
CGPlayer-SDL.cpp
/* Copyright [c] 2018-2028 www.chungen90.com Allrights Reserved*/
#ifndef CG_SDL_RENDER_H
#define CG_SDL_RENDER_H

#include <SDL.h>
#include <windows.h>
#include <mutex>
namespace ChunGen { namespace Client { namespace Player {

    class CGBlockRingBuffer
    {
    public:
        CGBlockRingBuffer()
            :buffer(nullptr)
            ,bufferSize(0)
            ,writeIndex(0)
            ,readIndex(0)
            ,bytesCanRead(0)        
        {
            
        }

        void Init(int buffSize)
        {

            buffer =  new uint8_t [buffSize];
            if(!buffer) return;
            this->bufferSize = buffSize;
        }

        void Write(uint8_t *src, int size)
        {
            if(!src ||size == 0) return ;
            std::lock_guard<std::mutex> lk(lock);
            int bytesCanWrite = size < bufferSize - bytesCanRead ? size : (bufferSize - bytesCanRead);

            if(bytesCanWrite <= bufferSize - writeIndex)
            {
                memcpy(buffer + writeIndex,src,bytesCanWrite);
                writeIndex += bytesCanWrite;
                if(writeIndex == bufferSize)
                {
                    writeIndex = 0;
                }
            }
            else
            {
                int room = bufferSize - writeIndex;
                memcpy(buffer + writeIndex, src,room);
                int left = bytesCanWrite - room;
                memcpy(buffer, src + room, left);
                writeIndex = left;
            }
            bytesCanRead += bytesCanWrite;

        }

        int Read(uint8_t *dst, int size)
        {
            if(!dst || size == 0) return 0;
            std::lock_guard<std::mutex> lk(lock);
            int bytesRead = size < bytesCanRead ? size : bytesCanRead;
            if(bytesRead <= bufferSize - readIndex)
            {
                memcpy(dst,buffer + readIndex,bytesRead);
                readIndex += bytesRead;
                if(readIndex == bufferSize) readIndex = 0;
            }
            else
            {
                int bytesHead = bufferSize - readIndex;
                memcpy(dst, buffer + readIndex,bytesHead);
                int bytesTail = bytesRead - bytesHead;
                memcpy(dst + readIndex,buffer, bytesTail);
                readIndex = bytesTail;
            }
            bytesCanRead -= bytesRead;
            return bytesRead;
        }
    private:
        uint8_t *buffer;
        int bufferSize;
        int readIndex;
        int  writeIndex;
        int bytesCanRead;
        std::mutex lock;
    };

    class CGSDLRender 
    {
    public:
        CGSDLRender();
        virtual ~CGSDLRender(void);
        
        int InitVideo(HWND hDisplayWindow, int adapterId = 0);

        int CreateVideoSurface(int width, int height);
        int Display(BYTE** data, int* linesize);
        

        int InitAudio(int samples,int channels);
        int PlaySamples(BYTE* buffer, int size) ;
        void Close();
    private:

        SDL_Window *sdlWindow;
        SDL_Renderer *sdlRender;
        SDL_Texture *sdlTexture;

        int width;
        int height;

        CGBlockRingBuffer  *blockingBuffer;
        //CircularBuffer *blockingBuffer;
    private:
    
    };

    
}}}
#endif
CGSdlRender.h
/* Copyright [c] 2018-2028 www.chungen90.com Allrights Reserved*/
#include "pch.h"
#include "CGSDLRender.h"
using namespace ChunGen::Client::Player;

    void  callback(void *userdata, Uint8 *stream, int len) {
        if(userdata != nullptr)
        {
            CGBlockRingBuffer* blockingBuffer = (CGBlockRingBuffer*)userdata;
            auto len1 = 0;
            while (len > 0)
            {
                len1 = blockingBuffer->Read((uint8_t*)stream + len1,len);
                len = len - len1;
            }
            
        }
    }

    CGSDLRender::CGSDLRender()
        :blockingBuffer(nullptr)
    {

    }

    CGSDLRender::~CGSDLRender()
    {
        
    }

    int CGSDLRender::InitVideo(HWND hDisplayWindow, int adapterId)
    {
        SDL_Init(SDL_INIT_VIDEO);
        sdlWindow = SDL_CreateWindowFrom(hDisplayWindow);
        sdlRender = SDL_CreateRenderer(sdlWindow, -1, SDL_RendererFlags::SDL_RENDERER_ACCELERATED);
        return S_OK;
    }

    int CGSDLRender::CreateVideoSurface(int width, int height)
    {
        this->width = width;
        this->height = height;
        sdlTexture = SDL_CreateTexture(sdlRender, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, width, height);
        return S_OK;
    }

    int CGSDLRender::Display(BYTE** data, int* linesize)
    {
        void* piexels = nullptr;
        int pitch;

        int ret = SDL_LockTexture(sdlTexture, NULL, &piexels, &pitch);
        if(ret < 0) return ret;
        uint8_t*    yuv[3] = { 
            (uint8_t*)piexels,(uint8_t*)piexels + pitch * height,
            (uint8_t*)piexels + pitch * height + ((pitch >> 1) * (height >> 1))
            };
    
            for (int i = 0; i < height; i++)
            {
                memcpy(yuv[0] + i * pitch, data[0] + i * linesize[0], linesize[0]);
                if (i % 2 == 0)
                {
                    memcpy(yuv[1] + (i >> 1) * (pitch >> 1), data[2] + (i >> 1) * linesize[2], linesize[2]);
                    memcpy(yuv[2] + (i >> 1) * (pitch >> 1), data[1] + (i >> 1) * linesize[1], linesize[1]);
                }
            }
        

        SDL_UnlockTexture(sdlTexture);
        SDL_RenderClear(sdlRender);
        SDL_RenderCopy(sdlRender, sdlTexture, NULL, NULL);
        SDL_RenderPresent(sdlRender);
        return S_OK;
    }



    void CGSDLRender::Close()
    {
        SDL_CloseAudio();
        if(blockingBuffer)
        {
            delete blockingBuffer;
        }
        
    }

    int CGSDLRender::InitAudio(int samples,int channels)
    {
        SDL_Init(SDL_INIT_AUDIO);
        blockingBuffer = new CGBlockRingBuffer();
        blockingBuffer->Init(4 * 1024);
        SDL_AudioSpec wanted;
        wanted.freq = samples;
        wanted.format = AUDIO_S16SYS;
        wanted.channels = channels > 2 ? 2 : channels;
        wanted.silence = 0;
        wanted.samples = 1024;
        wanted.callback = callback;
        wanted.userdata = this->blockingBuffer;
    //    devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &wanted, &spec, SDL_AUDIO_ALLOW_ANY_CHANGE);
        auto r = (SDL_OpenAudio(&wanted,NULL));
        SDL_PauseAudio(0);
        return r;

    }
    int CGSDLRender::PlaySamples(BYTE* buffer, int size) {
        this->blockingBuffer->Write(buffer,size);
         //SDL_QueueAudio(1,buffer,size);
        return S_OK;
    }
CGSdlRender.cpp
/* Copyright [c] 2018-2028 www.chungen90.com Allrights Reserved*/
#ifndef SDL_PLAYER_H
#define SDL_PLAYER_H
#include <string>
#include "pch.h"
#include <memory>
#include "CGSdlRender.h"
#include <thread>
#define DelayTime 5
namespace ChunGen{ namespace Client {namespace  Player
{
    enum  CGPlayState
    {
        PClose = 0,
        POpen,
        PStart
    };

    class SdlPlayer
    {
    public:
        SdlPlayer()
            :inputContext(nullptr)
            ,lastReadPacktTime(av_gettime())
            ,timeout(10)
            ,sdlRender(nullptr)
            ,videoIndex(-1)
            ,audioIndex(-1)
            ,playState(CGPlayState::PClose)
            ,swr(nullptr)
            ,lastDts(-1)
            ,seekTime(-1)
        {

        }

        void Init()
        {
            av_register_all();
            avfilter_register_all();
            avformat_network_init();
            av_log_set_level(AV_LOG_ERROR);
        }

        int OpenInput(std::string inputUrl)  //rtsp://admin:admin12345@192.168.1.64:554/h264/ch1/main/av_stream
        {
            inputContext = avformat_alloc_context();    
            lastReadPacktTime = av_gettime();
            inputContext->interrupt_callback.opaque = this;
            inputContext->interrupt_callback.callback = interrupt_cb;
            int ret = avformat_open_input(&inputContext, inputUrl.c_str(), nullptr,nullptr);
            if(ret < 0)
            {
                av_log(NULL, AV_LOG_ERROR, "Input file open input failed\n");
                return  ret;
            }
            ret = avformat_find_stream_info(inputContext,nullptr);
            if(ret < 0)
            {
                av_log(NULL, AV_LOG_ERROR, "Find input file stream inform failed\n");
            }
            else
            {
                for(int i = 0; i < inputContext->nb_streams; i++)
                {
                    if(inputContext->streams[i]->codec->codec_type == AVMediaType::AVMEDIA_TYPE_VIDEO)
                    {
                        videoIndex  = i;
                    }
                    else if(inputContext->streams[i]->codec->codec_type == AVMediaType::AVMEDIA_TYPE_AUDIO)
                    {
                        audioIndex = i;
                    }
                }
                playState = CGPlayState::POpen;
                av_log(NULL, AV_LOG_FATAL, "Open input file  %s success\n",inputUrl.c_str());
            }
            return ret;
        }

        int  Play(HWND handle)
        {
            int ret = -1;
            if(playState != CGPlayState::POpen)  ret;

            sdlRender =std::make_shared<CGSDLRender>();
            if(videoIndex >= 0)
            {
                ret = initVideoDecodeContext();
                if(ret < 0) return ret;
                sdlRender->InitVideo(handle,0);
                sdlRender->CreateVideoSurface(inputContext->streams[videoIndex]->codec->width, inputContext->streams[videoIndex]->codec->height);
            }
            if(audioIndex >= 0)
            {     
                ret = initAudioDecodeContext();
                if(ret < 0) return ret;

                sdlRender->InitAudio(inputContext->streams[audioIndex]->codec->sample_rate,inputContext->streams[audioIndex]->codec->channels);            
            }
            playState = CGPlayState::PStart;
            task.swap(std::thread([=]{

                AVFrame * videoFrame = av_frame_alloc();
                AVFrame * audioFrame = av_frame_alloc();
                while(playState == CGPlayState::PStart)
                {
                    auto packet = readPacketFromSource();
                    if(packet)
                    {
                        if(packet->stream_index == videoIndex)
                        {
                            if(videoDecode(packet.get(),videoFrame))
                            {
                                playVideo(videoFrame);
                            }
                            if(lastDts >= 0)
                            {
                                auto diff = packet->dts - lastDts;
                                int duration = diff * 1000 /(inputContext->streams[videoIndex]->time_base.den
                                    /inputContext->streams[videoIndex]->time_base.num);
                                if(duration > DelayTime && duration < 1000)
                                {
                                    Sleep(duration - DelayTime);
                                }
                            }
                            lastDts = packet->dts;
                            if(seekTime > 0)
                            {
                                seek(seekTime, 0);
                                seekTime = -1;
                            }
                        }
                        else if(packet->stream_index == audioIndex)
                        {
                            if(audioDecode(packet.get(),videoFrame))
                            {
                                playAudio(videoFrame);
                            }
                        }
                    }

                }
                av_frame_free(&videoFrame);
                av_frame_free(&audioFrame);
            }));
            return ret;
        }

        void Seek( int64_t seekTime)
        {
            this->seekTime = seekTime;
        }

        int GetDurtion()
        {
            if(inputContext)
            {
                return inputContext->duration / 1000000;
            }
            return 0;
        }
        void Close()
         {
             playState = CGPlayState::PClose;
             if(sdlRender)
             {
                 sdlRender->Close();
                 sdlRender = nullptr;
             }
             if(task.joinable())
             {
                 task.join();
             }
            if(inputContext)
            {
                for(int i = 0 ; i < inputContext->nb_streams; i++)
                {
                    AVCodecContext *codecContext = inputContext->streams[i]->codec;
                    avcodec_close(codecContext);
                }
                avformat_close_input(&inputContext);
                inputContext = nullptr;
            }
            if(swr)
            {
                swr_free(&swr);
                swr = nullptr;
            }
         }
    private:
        static int interrupt_cb(void *ctx)
        {
            SdlPlayer* sdlPlayer = (SdlPlayer* )ctx;

            if(av_gettime() - sdlPlayer->lastReadPacktTime > sdlPlayer->timeout *1000 *1000)
            {
                return -1;
            }
            return 0;
        }
        std::shared_ptr<AVPacket> readPacketFromSource()
        {
            std::shared_ptr<AVPacket> packet(static_cast<AVPacket*>(av_malloc(sizeof(AVPacket))), [&](AVPacket *p) { av_packet_free(&p); av_freep(&p);});
            av_init_packet(packet.get());
            lastReadPacktTime = av_gettime();
            int ret = av_read_frame(inputContext, packet.get());
            if(ret >= 0)
            {
                return packet;
            }
            else
            {
                return nullptr;
            }

        }        

        int initVideoDecodeContext()
        {    
            auto codecId = inputContext->streams[videoIndex]->codec->codec_id;
            auto codec = avcodec_find_decoder(codecId);
            if (!codec)
            {
                return -1;
            }

            int ret = avcodec_open2(inputContext->streams[videoIndex]->codec, codec, NULL);
            return ret;

        }

        bool videoDecode(AVPacket* packet, AVFrame *frame)
        {
            int gotFrame = 0;
            auto hr = avcodec_decode_video2(inputContext->streams[videoIndex]->codec, frame, &gotFrame, packet);
            if (hr >= 0 && gotFrame != 0)
            {
                return true;
            }
            return false;
        }

        int initAudioDecodeContext()
        {    
            int ret  = -1;
            auto codecId = inputContext->streams[audioIndex]->codec->codec_id;
            auto codec = avcodec_find_decoder(codecId);
            if (!codec)
            {
                return ret;
            }

            ret = avcodec_open2(inputContext->streams[audioIndex]->codec, codec, NULL);
            if(ret < 0) return ret;

            if(inputContext->streams[audioIndex]->codec->sample_fmt != AV_SAMPLE_FMT_S16)
            {
                swr = swr_alloc();
                av_opt_set_int(swr, "in_channel_layout", inputContext->streams[audioIndex]->codec->channel_layout, 0);
                av_opt_set_int(swr, "out_channel_layout", inputContext->streams[audioIndex]->codec->channel_layout,  0);
                av_opt_set_int(swr, "in_sample_rate",     inputContext->streams[audioIndex]->codec->sample_rate, 0);
                av_opt_set_int(swr, "out_sample_rate",    inputContext->streams[audioIndex]->codec->sample_rate, 0);
                av_opt_set_sample_fmt(swr, "in_sample_fmt",  inputContext->streams[audioIndex]->codec->sample_fmt, 0);
                av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16,  0);
                swr_init(swr);
            }        
            return ret;
        }

        bool audioDecode(AVPacket* packet, AVFrame *frame)
        {
            int gotFrame = 0;
            auto hr = avcodec_decode_audio4(inputContext->streams[audioIndex]->codec, frame, &gotFrame, packet);
            if (hr >= 0 && gotFrame != 0)
            {
                return true;
            }
            return false;
        }

        void playVideo(AVFrame* frame)
        {
            sdlRender->Display(frame->data,frame->linesize);
        }

        void playAudio(AVFrame* frame)
        {            
            if(swr)
            {
                int dstNbChannels = 1;
                int srcNbSamples = frame->nb_samples;
                int srcRate =inputContext->streams[audioIndex]->codec->sample_rate;
                int dstRate = inputContext->streams[audioIndex]->codec->sample_rate;
                int dstNbSamples = av_rescale_rnd(srcNbSamples, dstRate, srcRate, AV_ROUND_UP);
                AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16;

                uint8_t** dst_data = nullptr;
                int dstLinesize;
                dstNbChannels = av_get_channel_layout_nb_channels(inputContext->streams[audioIndex]->codec->channel_layout);
                dstNbChannels = dstNbChannels > 0 ? dstNbChannels : 1;
                int ret = av_samples_alloc_array_and_samples(&dst_data, &dstLinesize, dstNbChannels, dstNbSamples, dst_sample_fmt, 0);

                ret = swr_convert(swr, dst_data, dstNbSamples, (const uint8_t **)frame->data, srcNbSamples);

                sdlRender->PlaySamples((BYTE*)dst_data[0], dstLinesize);
                if (dst_data)
                {
                    av_freep((void*)&dst_data[0]);
                }
                av_freep(&dst_data);
            }
            else
            {                    
                sdlRender->PlaySamples(frame->data[0], frame->linesize[0]);
            }

        }

        void seek( int64_t seekTime,int streamIndex)
        {
            int defaultStreamIndex = av_find_default_stream_index(inputContext);            
            auto time_base = inputContext->streams[defaultStreamIndex]->time_base;
            auto newDts = inputContext->streams[defaultStreamIndex]->start_time + av_rescale(seekTime, time_base.den, time_base.num);
            if(newDts > inputContext->streams[streamIndex]->cur_dts)
            {
                av_seek_frame(inputContext, defaultStreamIndex, newDts, AVSEEK_FLAG_ANY);
            }
            else
            {
                av_seek_frame(inputContext, defaultStreamIndex, newDts, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
            }
        }
    private:
        AVFormatContext *inputContext;
        int64_t lastReadPacktTime ;
        int timeout;
        std::shared_ptr<CGSDLRender> sdlRender;
        std::thread task;
        int videoIndex;
        int audioIndex;
        CGPlayState playState;
        SwrContext* swr;
        int64_t lastDts;
        int seekTime;
    };
}}};
#endif
SdlPlayer.h

 

posted @ 2022-01-21 11:34  泽良_小涛  阅读(34)  评论(0编辑  收藏  举报