• 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;
    
    }
  • 相关阅读:
    TCP服务器是否需要心跳包?
    用最简单的函数实现功能:判断一个int数据是否是2的x次幂(不能使用循环)。
    防止程序启动两次的方法CreateMutex()
    WINDOWS操作系统中可以允许最大的线程数
    setsockopt 设置socket 详细用法
    我的结论:DX9不支持非2的次幂尺寸纹理,还得显卡说了算
    D3DX_DEFAULT_NONPOW2
    【解决】Select网络模型问题——奇怪的发送接收问题
    CRC32 简单使用
    .NET开发总结 2010年2月
  • 原文地址:https://www.cnblogs.com/cnchengv/p/15407973.html
Copyright © 2020-2023  润新知