• 音频player


    #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 <windows.h>
    #include "sdlplayer.h"
    
    AVInputFormat mFormat;
    AVDictionary* iformat_opts;
    using namespace std;
    
    
    
    int audioIndex = 0;
    SwrContext* swr;
    AVFormatContext *inputContext = NULL;
    int64_t lastReadPacktTime ;
    
    int mymain();
    //extern "C" _declspec(dllexport) int mymain();
    
    int _tmain(int argc, _TCHAR* argv[]){
        mymain();
        return 0;
    }
    
    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(inputContext, packet.get());
        if(ret >= 0)
        {
            return packet;
        }
        else
        {
            return nullptr;
        }
    }    
    
    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;
    }
    
    std::shared_ptr<CGSDLRender> sdlRender =std::make_shared<CGSDLRender>();
    
    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[0]->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]);
        }
    }
    
    int mymain()
    {
        int scan_all_pmts_set = 0;
        /* register all codecs, demux and protocols */
        Init();
        inputContext = avformat_alloc_context();
        int ret;
        if (!inputContext) {
            av_log(NULL, AV_LOG_FATAL, "Could not allocate context.
    ");
            ret = AVERROR(ENOMEM);
            printf("alloc err %d
    ",ret);
    
        }
    
        //int err = avformat_open_input(&inputContext, "F://output.m4a", nullptr, nullptr);
        int err = avformat_open_input(&inputContext, "F://test.mp4", nullptr, nullptr);
        //int err = avformat_open_input(&inputContext, "F://3s.mp4", nullptr, nullptr);
        //int err = avformat_open_input(&inputContext, "F://sax.mp3", nullptr, nullptr);
        //int err = avformat_open_input(&inputContext, "F://Alarm01.wav", nullptr, nullptr);
        
        if (err < 0) {
            printf("open err err=%d
    ",err);
        }
        err = avformat_find_stream_info(inputContext, nullptr);
    
        printf("ic->nb_streams %d
    ",inputContext->nb_streams);
        if(err<0){
            printf("Find input file stream inform failed
    ");
        }else{
            for(int i=0;i<inputContext->nb_streams;i++){
    
                int type =  inputContext->streams[i]->codec->codec_type;
                printf("type = %d
    ",type);
                if(inputContext->streams[i]->codec->codec_type == AVMediaType::AVMEDIA_TYPE_AUDIO)
                {
                    audioIndex  = i;
                }
            }                                        
        }
    
        ret = initAudioDecodeContext();
        if(ret < 0) return ret;
    
        sdlRender->InitAudio(inputContext->streams[audioIndex]->codec->sample_rate,inputContext->streams[audioIndex]->codec->channels);    
    
    
        AVFrame * videoFrame = av_frame_alloc();
    
        for(int i=0;;i++){
            auto packet = readPacketFromSource();
            if(packet){
                if(packet->stream_index==audioIndex)
                    if(audioDecode(packet.get(),videoFrame)){
    
                     printf("packet->pts time =%d
     ",1000*packet->pts/(inputContext->streams[audioIndex]->time_base.den
                            /inputContext->streams[audioIndex]->time_base.num));
                        playAudio(videoFrame);
                        //Sleep(1);
                    }                
            }
            else{
                printf("i=%d Sleep--->
    ",i);
                break;
            }
        }
        printf("Sleep--->
    ");
        Sleep(20000);
    
        av_frame_free(&videoFrame);
        return 0;
    }

    sdlplayer.h

    #ifndef SDL_PLAYER_H
    #define SDL_PLAYER_H
    
    #include <SDL.h>
    #include <windows.h>
    #include <mutex>
    
        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 InitAudio(int samples,int channels);
        int PlaySamples(BYTE* buffer, int size) ;
        void Close();    
    
        CGBlockRingBuffer  *blockingBuffer;
    private:
        
    };
    
        
    
    
    #endif

    sdlplayer.cpp

    #include <SDL.h>
    #include <windows.h>
    #include "sdlplayer.h"
    
    void  callback(void *userdata, Uint8 *stream, int len) {
        SDL_memset(stream, 0, 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;
                //printf("len1 len %d,%d 
    ",len1,len);
            }
                
        }
    }
    
    CGSDLRender::~CGSDLRender()
    {
    
    }
    CGSDLRender::CGSDLRender()
    {
    
    }
    
    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 * 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);
        //printf("size = %d 
    ",size);
            //SDL_QueueAudio(1,buffer,size);
        return S_OK;
    }
  • 相关阅读:
    UVA 10935 约瑟夫环
    分拆素数和 埃氏筛法
    POJ 2349 Prim
    POJ 2031 prim
    POJ 1861 Kruskal
    POJ 2395 Prim
    POJ 1751 Prim
    POJ 2421 Prim
    vuejs开发环境搭建及热更新
    vuejs介绍
  • 原文地址:https://www.cnblogs.com/cnchengv/p/14389951.html
Copyright © 2020-2023  润新知