pla

sdltest1.cpp

// sdltest1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
extern "C"
{
    #include <SDL.h>
    #include "libavutil/opt.h"
    #include "libavutil/channel_layout.h"
    #include "libavutil/common.h"
    #include "libavutil/imgutils.h"
    #include "libavutil/mathematics.h"
    #include "libavutil/samplefmt.h"
    #include "libavutil/time.h"
    #include "libavutil/fifo.h"
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavformat/avio.h"
    #include "libavfilter/avfiltergraph.h"
    #include "libavfilter/avfilter.h"
    #include "libavfilter/buffersink.h"
    #include "libavfilter/buffersrc.h"
    #include "libswscale/swscale.h"
    #include "libswresample/swresample.h"
}
#include <memory>
#include <vector>
#include <windows.h>
#include <thread>
#include <mutex>
#include <queue>
#include <iostream>
#include "sdlplayer.h"

#pragma comment(lib, "avcodec.lib")
using namespace std;


//int mymain();
//extern "C" _declspec(dllexport) int mymain();

int mymain(char* file);
//int _tmain(int argc, _TCHAR* argv[])
int main(int argc, char* argv[])
{
    printf("come this -->
");
    if(argc!=2) {
        printf("Args count not right!
");
        //return 0;
    }

    printf("%s 
",(char*)argv[1]);
    mymain((char*)argv[1]);
    return 0;
}


#define INBUF_SIZE 4096
#define DelayTime 5

typedef struct  {
    std::shared_ptr<BYTE> buf;
    BYTE*    data[3];
    int      linesize[AV_NUM_DATA_POINTERS];
    int64_t  dts;
} DecodeVideoFrame;

typedef struct  {
    std::shared_ptr<BYTE> buf;
    BYTE*    data;
    int      linesize;
    int      startPos;
    double   dpts;
} DecodeAudioFrame;


int videoIndex = -1;
int audioIndex = -1;
AVInputFormat mFormat;
AVDictionary* iformat_opts;
AVFormatContext *ic = NULL;
int64_t lastReadPacktTime;

queue<std::shared_ptr<DecodeVideoFrame>> quePicFrame;

queue<std::shared_ptr<DecodeAudioFrame>> queSmpFrame;

int gWidth = 0;
int gHeight = 0;
int playState = 1;
std::shared_ptr<CGSDLRender> sdlRender;
mutex   g_lock;
int64_t lastDts = 0;
unsigned long lastTime = 0;
SwrContext* swr;

double audio_clock = 0.;
double video_clock = 0.;


void  fill_audio(void *userdata, Uint8 *stream, int len) {

    SDL_memset(stream, 0, len);
    if (queSmpFrame.size() == 0) return;
    if (video_clock <= 0.01) return;

    std::shared_ptr<DecodeAudioFrame> daf = queSmpFrame.front();

    int  leftLen = daf->linesize - daf->startPos;
    byte* buf = new byte[len];
    memset(buf,0,len);
    int startPos = 0;

    //daf->data

    if (len >= leftLen){
        memcpy(buf, daf->data + daf->startPos, leftLen);
        queSmpFrame.pop();
        int newlen = len - leftLen;
        //printf("newlen = %d -->
", newlen);
        audio_clock = daf->dpts;
        if (newlen > 0){
            auto daf2 = daf = queSmpFrame.front();
            memcpy(buf + leftLen, daf2->data, newlen);
            daf2->startPos = newlen;
            //printf("audio pts %.1f",daf2->dpts);
            audio_clock = daf2->dpts;
        }
        else{
            //printf("audio pts %.1f", daf->dpts);
        }
    }
    else{
        memcpy(buf, daf->data + daf->startPos, len);
        daf->startPos = daf->startPos + len;
        //printf("audio pts %.1f", daf->dpts);
        audio_clock = daf->dpts;
    }

    SDL_MixAudio(stream, buf, len, SDL_MIX_MAXVOLUME);
    //daf->startPos
}

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

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(ic, packet.get());
    if(ret >= 0){
        return packet;
    }else{
        return nullptr;
    }
}    

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

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

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

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

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

    if (ic->streams[audioIndex]->codec->sample_fmt != AV_SAMPLE_FMT_S16)
    {
        swr = swr_alloc();
        av_opt_set_int(swr, "in_channel_layout", ic->streams[audioIndex]->codec->channel_layout, 0);
        av_opt_set_int(swr, "out_channel_layout", ic->streams[audioIndex]->codec->channel_layout, 0);
        av_opt_set_int(swr, "in_sample_rate", ic->streams[audioIndex]->codec->sample_rate, 0);
        av_opt_set_int(swr, "out_sample_rate", ic->streams[audioIndex]->codec->sample_rate, 0);
        av_opt_set_sample_fmt(swr, "in_sample_fmt", ic->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(ic->streams[audioIndex]->codec, frame, &gotFrame, packet);
    if (hr >= 0 && gotFrame != 0)
    {
        return true;
    }
    return false;
}

void addAudioData(BYTE* buffer, int size, AVFrame* frame, double dPts){
    if (NULL == frame) return;
    std::shared_ptr<DecodeAudioFrame> dfr(static_cast<DecodeAudioFrame*>(new DecodeAudioFrame), [&](DecodeAudioFrame *p) { delete p; });
    std::shared_ptr<BYTE> tmpbuf(new BYTE[size](), std::default_delete<BYTE[]>());
    dfr->buf = tmpbuf;
    dfr->data = dfr->buf.get();
    memcpy(dfr->data, buffer, size);

    dfr->linesize = size;
    dfr->startPos = 0;
    dfr->dpts = dPts;
    queSmpFrame.push(dfr);
}

void prepareAudioData(AVFrame* frame, double dPts)
{
    if (swr)
    {
        int dstNbChannels = 1;
        int srcNbSamples = frame->nb_samples;
        int srcRate = ic->streams[audioIndex]->codec->sample_rate;
        int dstRate = ic->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(ic->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);

        addAudioData((BYTE*)dst_data[0], dstLinesize, frame, dPts);

        if (dst_data){
            av_freep((void*)&dst_data[0]);
        }
        av_freep(&dst_data);
    }
    else
    {
        addAudioData(frame->data[0], frame->linesize[0], frame, dPts);
    }
}

void playFun(){
    
    for(;;){
        if(playState == 0) break;
        if (quePicFrame.size()>0){

            g_lock.lock();
            std::shared_ptr<DecodeVideoFrame> dfr = quePicFrame.front();

            quePicFrame.pop();
            g_lock.unlock();
            auto diff = dfr->dts - lastDts;

            int duration = diff * 1000 /(ic->streams[videoIndex]->time_base.den
                        /ic->streams[videoIndex]->time_base.num);

            if(duration > DelayTime && duration < 1000){
                //Sleep(duration );
            }
            //std::cout<<"duration1: "<<duration<<endl;

            video_clock = dfr->dts * 1000 / (ic->streams[videoIndex]->time_base.den
                / ic->streams[videoIndex]->time_base.num);
            int diff2 = video_clock - audio_clock;

            printf("v %.1f a %.1f --->
", video_clock, audio_clock);
            if (diff2 > 100){
                Sleep(100);
            }else if(diff2 > 0){
                Sleep(duration);
            }else if (diff2 < 0){
                continue;
            }
            
            printf("video pts =%.1f --->
 ", video_clock);

            sdlRender->Display((char**)dfr->data, dfr->linesize);
            lastDts = dfr->dts;
            unsigned long nowTime = GetTickCount();
            //这个需要释放,to thi--------???
            lastTime = nowTime;
            
        }else{
            Sleep(150);
        }
    }
}


int mymain(char* file){
    int scan_all_pmts_set = 0;
    /* register all codecs, demux and protocols */
    Init();
    ic = avformat_alloc_context();
    int ret;
    if (!ic) {
        av_log(NULL, AV_LOG_FATAL, "Could not allocate context.
");
        ret = AVERROR(ENOMEM);
        printf("alloc err %d
",ret);
    }
                                        //"F://3s.mp4"
    int err = avformat_open_input(&ic, "F://test.mp4", nullptr, nullptr);
    if (err < 0) {
        printf("open err err=%d
",err);
    }

    err = avformat_find_stream_info(ic, nullptr);
    printf("ic->nb_streams %d
",ic->nb_streams);
    if(err<0){

    }else{
        for(int i=0;i<ic->nb_streams;i++){
            int type =  ic->streams[i]->codec->codec_type;
            printf("type = %d
",type);
            if(type == AVMediaType::AVMEDIA_TYPE_VIDEO){
                videoIndex  = i;
                printf("videoIndex =%d 
",videoIndex);
            }
            else if (type == AVMediaType::AVMEDIA_TYPE_AUDIO){
                audioIndex = i;
            }
        }                                        
    }

    gWidth  = ic->streams[videoIndex]->codec->width;
    gHeight = ic->streams[videoIndex]->codec->height;

    if (videoIndex >= 0)
    {
        int ret1 = initVideoDecodeContext();
        printf("ret1 = %d
", ret1);
        //std::shared_ptr<CGSDLRender>
        sdlRender = std::make_shared<CGSDLRender>();//???????
        ret = initVideoDecodeContext();
        if (ret < 0) return ret;
        sdlRender->InitVideo(0);
    }
    if (audioIndex >= 0)
    {
        ret = initAudioDecodeContext();
        if (ret < 0) return ret;

        sdlRender->InitAudio(ic->streams[audioIndex]->codec->sample_rate, ic->streams[audioIndex]->codec->channels);
    }

    sdlRender->CreateVideoSurface(gWidth, gHeight);
    AVRational time_base =ic->streams[videoIndex]->time_base;
    printf("num %d,den %d--
",time_base.num,time_base.den);

    playState = 1;
    thread t1(playFun);
    t1.detach();
    int64_t lastDts=0;

    int w = gWidth;
    int h = gHeight;
    AVFrame * videoFrame = av_frame_alloc();
    for(int i=0;i<10000;i++){
        auto packet = readPacketFromSource();
        if(packet){
            if(packet->stream_index==videoIndex){
                
                if(videoDecode(packet.get(),videoFrame))
                {
                    printf("%d---
",i);
                    std::shared_ptr<DecodeVideoFrame> dfr(static_cast<DecodeVideoFrame*>(new DecodeVideoFrame), [&](DecodeVideoFrame *p) { delete p; });

                    std::shared_ptr<BYTE> tmpbuf (new BYTE[w * h * 3 / 2 + 100](), std::default_delete<BYTE[]>());
                    dfr->buf = tmpbuf;

                    memcpy(dfr->buf.get(),videoFrame->data[0],w*h);
                    memcpy(dfr->buf.get() + w * h, videoFrame->data[1], w * h / 4);
                    memcpy(dfr->buf.get() + w * h * 5 / 4, videoFrame->data[2], w * h / 4);
                    dfr->data[0] = dfr->buf.get();
                    dfr->data[1] = dfr->buf.get() + w * h;
                    dfr->data[2] = dfr->buf.get() + w * h * 5 / 4;
                    dfr->dts = packet->dts;
                
                    memcpy(dfr->linesize, videoFrame->linesize, AV_NUM_DATA_POINTERS*sizeof(int));

                    g_lock.lock();
                    quePicFrame.push(dfr);
                    g_lock.unlock();
                    /*
                    printf("packet->dts time =%d 
 ",dfr->dts*1000/(ic->streams[videoIndex]->time_base.den
                    /ic->streams[videoIndex]->time_base.num));*/
                    if (quePicFrame.size()>30)
                            Sleep(100);

                }
            }
            else if (packet->stream_index == audioIndex)
            {
                if (audioDecode(packet.get(), videoFrame)){
                    int64_t pts = packet->pts;
                    double dpts = pts * 1000 / (ic->streams[audioIndex]->time_base.den
                        / ic->streams[audioIndex]->time_base.num);
                    prepareAudioData(videoFrame, dpts);
                }
            }
        }
        else{
            break;
        }
    }
    av_frame_free(&videoFrame);

    Sleep(8000);
    playState = 0;
    Sleep(600);
    system("PAUSE");
    
    return 0;
}

sdlplayer.h

#include <mutex>

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

    int CreateVideoSurface(int width, int height);
    int Display(char** 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;
private:
    
};

sdlplayer.cpp

#include <SDL.h>
#include <windows.h>
#include "sdlplayer.h"

extern void  fill_audio(void *userdata, Uint8 *stream, int len);

CGSDLRender::~CGSDLRender()
{

}
CGSDLRender::CGSDLRender() //:blockingBuffer(nullptr)
{

}

int CGSDLRender::InitVideo( int adapterId)
{
    SDL_Init(SDL_INIT_VIDEO);
    sdlWindow = SDL_CreateWindow(("窗口标题"),500,790,150,150,SDL_WINDOW_SHOWN);
    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(char** 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();

}

int CGSDLRender::InitAudio(int samples, int channels)
{
    SDL_Init(SDL_INIT_AUDIO);

    SDL_AudioSpec wanted;
    wanted.freq = samples;
    wanted.format = AUDIO_S16SYS;
    wanted.channels = channels > 2 ? 2 : channels;
    wanted.silence = 0;
    wanted.samples = 1024;
    wanted.callback = fill_audio;
    auto r = (SDL_OpenAudio(&wanted, NULL));
    SDL_PauseAudio(0);
    return r;

}
原文地址:https://www.cnblogs.com/cnchengv/p/15407973.html