ffmpeg+sdl播放类

来源:互联网 发布:源码下载站网站源码 编辑:程序博客网 时间:2024/05/16 05:47

前段时间一直捣鼓ffmpeg,觉得还是VLC比较亲切大哭,虽然我现在都不知道VLC怎么用了。

除了雷神的博客,主要参考的还是这个博客:http://blog.yundiantech.com/?log=index

自己在Qt下做了一个功能简单的播放类(播放,暂停,停止)。以后有时间再弄上快进,后退等。

/*********************************************************************************  *Copyright(C),ForMySelf  *FileName:GPlayer.h  *Author:gongluck  *Version:1.0  *Date: 2017-06-15  *Description:播放本地视频文件  *Others:  *Function List:  *History:     1.Date: 2017-06-15       Author: gongluck       Modification: 很早之前做的了,现在整理一下     2.Date: 2017-06-16       Author: gongluck       Modefication: 加上暂停等功能**********************************************************************************/#ifndef GPLAYER_H#define GPLAYER_H//Qt#include <QObject>#include <QImage>//stl#include <Queue>using namespace std;extern "C"{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libswscale/swscale.h"#include "libswresample/swresample.h"#include "SDL.h"#undef main}class GPlayer : public QObject{    Q_OBJECTpublic:    explicit GPlayer(QObject *parent = 0);    ~GPlayer();    bool SetFilename(const char* filename);    bool PlayFile(const char* filename = NULL);    bool Stop();    AVFormatContext* GetAVFormatCtx(){ return m_pFormatCtx; }    AVCodecContext* GetVCodecCtx() { return m_pVCodecCtx; }    AVCodecContext* GetACodecCtx() { return m_pACodecCtx; }    queue<AVPacket>& GetVPacketQue(){ return m_VpacketQue; }    queue<AVPacket>& GetAPacketQue(){ return m_ApacketQue; }    int GetVIndex() { return m_vindex; }    int GetAIndex() { return m_aindex; }    int GetDstWidth() { return m_dstWidth; }    int GetDstHeight() { return m_dstHeight; }    void SetDstWidth(int width) { m_dstWidth = width; }    void SetDstHeight(int height) { m_dstHeight = height; }    SDL_AudioSpec GetAudioSpec() { return m_AudioSpec; }    void SetPts(double pts) { m_pts = pts; }    double GetPts() { return m_pts; }    bool GetStopFlag() { return m_bStop; }    void SetStopFlag(bool bStop) { m_bStop = bStop; }    bool GetPauseFlag() { return m_bPause; }    void SetPauseFlag(bool bPause)    {        if(bPause)            SDL_PauseAudio(1);        else            SDL_PauseAudio(0);        m_bPause = bPause;    }    bool GetPlayingFlag() { return m_bPlaying; }    void SetPlayingFlag(bool bPause) { m_bPlaying = bPause; }signals:    void sig_picture(QImage);public slots:protected:    bool PreV();    bool PreA();private:    bool m_bInit;    char* m_filename;    unsigned int m_filenameLength;    AVFormatContext* m_pFormatCtx;    AVCodecContext* m_pVCodecCtx;    AVCodecContext* m_pACodecCtx;    AVCodec* m_pVCodec;    AVCodec* m_pACodec;    SDL_AudioSpec m_AudioSpec;    SDL_Thread* m_TReadPacket;    SDL_Thread* m_TPlayVideo;    queue<AVPacket> m_VpacketQue;    queue<AVPacket> m_ApacketQue;    int m_vindex;    int m_aindex;    int m_dstWidth;    int m_dstHeight;    double m_pts;    bool m_bStop;    bool m_bPause;    bool m_bPlaying;};#endif // GPLAYER_H

/*********************************************************************************  *Copyright(C),ForMySelf  *FileName:GPlayer.cpp  *Author:gongluck  *Version:1.0  *Date: 2017-06-15  *Description:播放本地视频文件  *Others:  *Function List:  *History:     1.Date: 2017-06-15       Author: gongluck       Modification: 很早之前做的了,现在整理一下     2.Date: 2017-06-16       Author: gongluck       Modefication: 加上暂停等功能**********************************************************************************/#include "GPlayer.h"int SDLCALL ReadPacket(void *data){    AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));    GPlayer* player = (GPlayer*)data;    AVFormatContext* pFormatCtx = player->GetAVFormatCtx();    queue<AVPacket>& VpacketQue = player->GetVPacketQue();    queue<AVPacket>& ApacketQue = player->GetAPacketQue();    int vindex = player->GetVIndex();    int aindex = player->GetAIndex();    av_init_packet(packet);    while(av_read_frame(pFormatCtx,packet) >= 0)    {        if(player->GetStopFlag())            break;        while(player->GetPauseFlag())        {            SDL_Delay(10);        }        if(packet->stream_index == vindex)        {            while(VpacketQue.size()>1023)            {                if(player->GetStopFlag())                    break;                SDL_Delay(10);            }            VpacketQue.push(*packet);        }        else if(packet->stream_index == aindex)        {            while(ApacketQue.size()>1023)            {                if(player->GetStopFlag())                    break;                SDL_Delay(10);            }            ApacketQue.push(*packet);        }        else        {            av_free_packet(packet);        }    }    av_free(packet);    return 0;}int SDLCALL PlayVideo(void *data){    AVFrame frame = {0};    AVFrame frameRGB = {0};    AVPacket packet = {0};    GPlayer* player = (GPlayer*)data;    AVFormatContext* pFormatCtx = player->GetAVFormatCtx();    AVCodecContext* pVCodecCtx = player->GetVCodecCtx();    queue<AVPacket>& VpacketQue = player->GetVPacketQue();    int vindex = player->GetVIndex();    int got_picture = 0;    struct SwsContext* img_convert_ctx = NULL;    int size = 0;    uint8_t* buf = NULL;    img_convert_ctx = sws_getContext(pVCodecCtx->width,pVCodecCtx->height,pVCodecCtx->pix_fmt                                     ,player->GetDstWidth(),player->GetDstHeight(),AV_PIX_FMT_RGB32,SWS_BICUBIC                                     ,NULL,NULL,NULL);    size = avpicture_get_size(AV_PIX_FMT_RGB32,player->GetDstWidth(),player->GetDstHeight());    buf = (uint8_t*)av_mallocz(sizeof(uint8_t) * size);    avpicture_fill((AVPicture*)&frameRGB,buf,AV_PIX_FMT_RGB32,player->GetDstWidth(),player->GetDstHeight());//把buf和frameRGB绑定    while(true)    {        if(player->GetStopFlag())            break;        else if(player->GetPauseFlag())        {            SDL_Delay(10);            continue;        }        if(VpacketQue.size() == 0)        {            SDL_Delay(10);            continue;        }        packet = VpacketQue.front();        if(avcodec_decode_video2(pVCodecCtx,&frame,&got_picture,&packet)<0)        {            av_free_packet(&packet);            VpacketQue.pop();            continue;        }        if(got_picture)        {            sws_scale(img_convert_ctx,frame.data,frame.linesize,0,pVCodecCtx->height,frameRGB.data,frameRGB.linesize);            QImage img(buf,player->GetDstWidth(),player->GetDstHeight(),QImage::Format_RGB32);//            while(frame.pkt_pts * av_q2d(pFormatCtx->streams[vindex]->time_base) > player->GetPts())//                SDL_Delay(1);            if(frame.pkt_pts * av_q2d(pFormatCtx->streams[vindex]->time_base) > player->GetPts())                  SDL_Delay((frame.pkt_pts*av_q2d(pFormatCtx->streams[vindex]->time_base) - player->GetPts()) *1000);            emit player->sig_picture(img);            VpacketQue.pop();        }    }    return 0;}void SDLCALL audioCallback(void *userdata, Uint8 * stream, int len){    AVFrame frame = {0};    AVPacket packet = {0};    GPlayer* player = (GPlayer*)userdata;    AVFormatContext* pFormatCtx = player->GetAVFormatCtx();    AVCodecContext* pACodecCtx = player->GetACodecCtx();    queue<AVPacket>& ApacketQue = player->GetAPacketQue();    int aindex = player->GetAIndex();    int got_picture = 0;    SDL_AudioSpec audiospec = player->GetAudioSpec();    static struct SwrContext* swr_convert_ctx = swr_alloc_set_opts(NULL,av_get_default_channel_layout(audiospec.channels),AV_SAMPLE_FMT_S16,audiospec.freq                                                            ,av_get_default_channel_layout(pACodecCtx->channels),pACodecCtx->sample_fmt,pACodecCtx->sample_rate                                                            ,NULL,NULL);    swr_init(swr_convert_ctx);    int size = av_samples_get_buffer_size(NULL,audiospec.channels,audiospec.samples,AV_SAMPLE_FMT_S16,1);    uint8_t* buf = (uint8_t*)av_mallocz(sizeof(uint8_t) * size);    while(ApacketQue.size() == 0)    {        if(player->GetStopFlag())            break;        SDL_Delay(10);    }    packet = ApacketQue.front();    if( avcodec_decode_audio4(pACodecCtx,&frame,&got_picture,&packet) < 0 )    {        av_free_packet(&packet);        ApacketQue.pop();        return ;    }    if(got_picture)    {        swr_convert(swr_convert_ctx,&buf,size,(const uint8_t**)frame.data,frame.nb_samples);        SDL_memset(stream,0,len);        SDL_MixAudio(stream,buf,len,SDL_MIX_MAXVOLUME);        player->SetPts(frame.pkt_pts * av_q2d(pFormatCtx->streams[aindex]->time_base));    }    av_free_packet(&packet);    ApacketQue.pop();    if(player->GetPauseFlag())        SDL_PauseAudio(1);    else        SDL_PauseAudio(0);}GPlayer::GPlayer(QObject *parent) : QObject(parent)  ,m_bInit(false)  ,m_filename(NULL)  ,m_filenameLength(0)  ,m_pFormatCtx(NULL)  ,m_vindex(-1)  ,m_aindex(-1)  ,m_pVCodecCtx(NULL)  ,m_pVCodec(NULL)  ,m_pACodecCtx(NULL)  ,m_pACodec(NULL)  ,m_AudioSpec{0}  ,m_pts(0.0)  ,m_bPause(false)  ,m_bStop(false){    //初始化ffmpeg    av_register_all();    //初始化SDL    if(SDL_Init(SDL_INIT_AUDIO) != 0)    {        m_bInit = false;    }    else    {        m_bInit = true;    }}GPlayer::~GPlayer(){    if(m_filename != NULL)    {        free(m_filename);        m_filename = NULL;        m_filenameLength = 0;    }}bool GPlayer::SetFilename(const char* filename){    if(m_filename != NULL)    {        free(m_filename);        m_filename = NULL;        m_filenameLength = 0;    }    m_filenameLength = strlen(filename)+1;    if(m_filenameLength<=0 || m_filenameLength>260)        return false;    m_filename = (char*)malloc(m_filenameLength);    if(m_filename == NULL)        return false;    strncpy(m_filename,filename,m_filenameLength);    return true;}bool GPlayer::PlayFile(const char* filename){    if(filename != NULL)    {        if(!SetFilename(filename))            return false;    }    if(m_pFormatCtx != NULL)        goto ERROR;    if(avformat_open_input(&m_pFormatCtx,m_filename,NULL,NULL)<0)        goto ERROR;    if(avformat_find_stream_info(m_pFormatCtx,NULL)<0)        goto ERROR;    if(!PreV() || !PreA())        goto ERROR;    SetStopFlag(false);    SetPauseFlag(false);    SetPlayingFlag(true);    m_TReadPacket = SDL_CreateThread(ReadPacket,"ReadPacket",this);    m_TPlayVideo = SDL_CreateThread(PlayVideo,"PlayVideo",this);    SDL_PauseAudio(0);    return true;ERROR:    if(m_pFormatCtx != NULL)        avformat_close_input(&m_pFormatCtx);    m_pVCodecCtx = m_pACodecCtx = NULL;    m_pVCodec = m_pACodec = NULL;    m_vindex = -1;    m_aindex = -1;    return false;}bool GPlayer::PreV(){    for(int i=0;i<m_pFormatCtx->nb_streams;++i)    {        if(m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)            m_aindex = i;        else if(m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)            m_vindex = i;    }    if(m_vindex==-1 || m_aindex==-1)        goto ERROR;    m_pVCodecCtx = m_pFormatCtx->streams[m_vindex]->codec;    m_pVCodec = avcodec_find_decoder(m_pVCodecCtx->codec_id);    if(avcodec_open2(m_pVCodecCtx,m_pVCodec,NULL) <0)        goto ERROR;    m_pACodecCtx = m_pFormatCtx->streams[m_aindex]->codec;    m_pACodec = avcodec_find_decoder(m_pACodecCtx->codec_id);    if(avcodec_open2(m_pACodecCtx,m_pACodec,NULL) <0)        goto ERROR;    return true;ERROR:    return false;}bool GPlayer::PreA(){    SDL_AudioSpec want = {0};    want.callback = audioCallback;    want.channels = m_pACodecCtx->channels;    want.format = AUDIO_S16SYS;//ffmpeg的格式与SDL的格式 不相同    want.freq = m_pACodecCtx->sample_rate;    want.samples = m_pACodecCtx->frame_size;//!!!    want.userdata = this;    if(SDL_OpenAudio(&want,&m_AudioSpec) != 0)        goto ERROR;    return true;ERROR:    return false;}bool GPlayer::Stop(){    m_bStop = true;    m_bPlaying = false;    SDL_CloseAudio();    if(m_pVCodecCtx != NULL)        avcodec_close(m_pVCodecCtx);    if(m_pACodecCtx != NULL)        avcodec_close(m_pACodecCtx);    if(m_pFormatCtx != NULL)        avformat_close_input(&m_pFormatCtx);    m_pFormatCtx = NULL;    m_pVCodecCtx = NULL;    m_pACodecCtx = NULL;    m_pVCodec = NULL;    m_pACodec = NULL;    memset(&m_AudioSpec,0,sizeof(m_AudioSpec));    m_TReadPacket = NULL;    m_TPlayVideo = NULL;    while(!m_VpacketQue.empty())    {        av_free_packet(&m_VpacketQue.front());        m_VpacketQue.pop();    }    while(!m_ApacketQue.empty())    {        av_free_packet(&m_ApacketQue.front());        m_ApacketQue.pop();    }    m_vindex = -1;    m_aindex = -1;//    m_dstWidth = 0;//    m_dstHeight = 0;    m_pts = 0;    return true;}

我自己最不喜欢别人不加注释,但是自己平常也不怎么写注释。吐舌头

工程地址