• 未同步的play


    CGSdlRender.h

    /* Copyright [c] 2017-2027 Gang.Wang Allrights Reserved*/
    #ifndef CG_SDL_RENDER_H
    #define CG_SDL_RENDER_H
    
    
    #include <windows.h>
    #include <mutex>
    #include "SDL.h"
    
    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;
            }
            int bytesCanRead;
        private:
            uint8_t *buffer;
            int bufferSize;
            int readIndex;
            int  writeIndex;
            
            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();
            CGBlockRingBuffer* blockingBuffer;
        private:
    
            SDL_Window *sdlWindow;
            SDL_Renderer *sdlRender;
            SDL_Texture *sdlTexture;
    
            int width;
            int height;
    
        
            //CircularBuffer *blockingBuffer;
        private:
        
        };
    
        
    }}}
    #endif

    CGSdlRender.cpp

    /* Copyright [c] 2017-2027 Gang.Wang 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| SDL_INIT_TIMER);
            //sdlWindow = SDL_CreateWindowFrom(hDisplayWindow);
            //sdlWindow = SDL_CreateWindow("Camera1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 320,
            //    240, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN| SDL_WINDOW_RESIZABLE);
            sdlWindow = SDL_CreateWindow("Camera1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 160,
                120, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
            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);
            blockingBuffer->Init(1*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);
             //SDL_QueueAudio(1,buffer,size);
            return S_OK;
        }

    demuxdecod.cpp

    #include <memory>
    #include <iostream>
    
    extern "C" {
        #include <libavutil/imgutils.h>
        #include <libavutil/samplefmt.h>
        #include <libavutil/timestamp.h>
        #include <libavformat/avformat.h>
        #include "libswresample/swresample.h"
    #include "libavutil/opt.h"
    }
    
    #include "CGSdlRender.h"
    using namespace ChunGen::Client::Player;
    
    static AVFormatContext* fmt_ctx = NULL;
    static AVCodecContext* video_dec_ctx = NULL, * audio_dec_ctx;
    static int width, height;
    static enum AVPixelFormat pix_fmt;
    static AVStream* video_stream = NULL, * audio_stream = NULL;
    static const char* src_filename = NULL;
    static const char* video_dst_filename = NULL;
    static const char* audio_dst_filename = NULL;
    //static FILE* video_dst_file = NULL;
    //static FILE* audio_dst_file = NULL;
    
    static uint8_t* video_dst_data[4] = { NULL };
    static int      video_dst_linesize[4];
    static int video_dst_bufsize;
    
    static int video_stream_idx = -1, audio_stream_idx = -1;
    static AVFrame* frame = NULL;
    static AVPacket* pkt = NULL;
    static int video_frame_count = 0;
    static int audio_frame_count = 0;
    
    std::shared_ptr<CGSDLRender> sdlRender;
    SDL_Thread* refresh_thread;
    SDL_Event event;
    SwrContext* swr;
    //Refresh Event
    #define REFRESH_EVENT  (SDL_USEREVENT + 1)
    
    int thread_exit = 0;
    int refresh_video(void* opaque) {
        while (thread_exit == 0) {
            SDL_Event event;
            event.type = REFRESH_EVENT;
            SDL_PushEvent(&event);
            SDL_Delay(40);
        }
        return 0;
    }
    
    static int output_video_frame(AVFrame* frame)
    {
        if (frame->width != width || frame->height != height ||
            frame->format != pix_fmt) {
            /* To handle this change, one could call av_image_alloc again and
             * decode the following frames into another rawvideo file. */
            fprintf(stderr, "Error: Width, height and pixel format have to be "
                "constant in a rawvideo file, but the width, height or "
                "pixel format of the input video changed:\n"
                "old: width = %d, height = %d, format = %s\n"
                "new: width = %d, height = %d, format = %s\n",
                width, height, av_get_pix_fmt_name(pix_fmt),
                frame->width, frame->height,
                av_get_pix_fmt_name((enum AVPixelFormat)frame->format));
            return -1;
        }
    
        printf("video_frame n:%d coded_n:%d\n",
            video_frame_count++, frame->coded_picture_number);
    
        /* copy decoded frame to destination buffer:
         * this is required since rawvideo expects non aligned data */
        av_image_copy(video_dst_data, video_dst_linesize,
            (const uint8_t**)(frame->data), frame->linesize,
            pix_fmt, width, height);
    
        /* write to rawvideo file */
        //  fwrite(video_dst_data[0], 1, video_dst_bufsize, video_dst_file);
    
        SDL_WaitEvent(&event);
        if (event.type == REFRESH_EVENT) {
            sdlRender->Display((uint8_t**)frame->data, frame->linesize);
        }
        else if (event.type == SDL_QUIT) {
           // break;
        }
        return 0;
    }
    
    static int output_audio_frame(AVFrame* frame)
    {
        size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample((enum AVSampleFormat)frame->format);
    
     
    
        char str[AV_TS_MAX_STRING_SIZE];
        printf(" audio_frame n:%d nb_samples:%d pts:%s \n",
            audio_frame_count++, frame->nb_samples,
           // av_ts2timestr(frame->pts, &audio_dec_ctx->time_base)
            av_ts_make_time_string(str, frame->pts, &audio_dec_ctx->time_base)
        );
    
        /* Write the raw audio data samples of the first plane. This works
         * fine for packed formats (e.g. AV_SAMPLE_FMT_S16). However,
         * most audio decoders output planar audio, which uses a separate
         * plane of audio samples for each channel (e.g. AV_SAMPLE_FMT_S16P).
         * In other words, this code will write only the first audio channel
         * in these cases.
         * You should use libswresample or libavfilter to convert the frame
         * to packed data. */
       // fwrite(frame->extended_data[0], 1, unpadded_linesize, audio_dst_file);
    
        if (swr)
        {
            int dstNbChannels = 1;
            int srcNbSamples = frame->nb_samples;
            int srcRate = audio_dec_ctx->sample_rate;
            int dstRate = audio_dec_ctx->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(audio_dec_ctx->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);
    
            //fwrite((BYTE*)dst_data[0], 1, dstLinesize, audio_dst_file);
    
            if (dst_data)
            {
                av_freep((void*)&dst_data[0]);
            }
            av_freep(&dst_data);
        }
        else
        {
            sdlRender->PlaySamples(frame->data[0], frame->linesize[0]);
        }
        while(sdlRender->blockingBuffer->bytesCanRead > 1024*20)
             SDL_Delay(1);
        return 0;
    }
    
    static int decode_packet(AVCodecContext* dec, const AVPacket* pkt)
    {
        int ret = 0;
    
        // submit the packet to the decoder
        ret = avcodec_send_packet(dec, pkt);
        if (ret < 0) {
            char str[AV_ERROR_MAX_STRING_SIZE];
            fprintf(stderr, "Error submitting a packet for decoding (%s)\n", 
                av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, ret)
               // av_err2str(ret)
            );
            return ret;
        }
    
        // get all the available frames from the decoder
        while (ret >= 0) {
            ret = avcodec_receive_frame(dec, frame);
            if (ret < 0) {
                // those two return values are special and mean there is no output
                // frame available, but there were no errors during decoding
                if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
                    return 0;
                char str[AV_ERROR_MAX_STRING_SIZE];
                fprintf(stderr, "Error during decoding (%s)\n", 
                    av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, ret)
                    //    av_err2str(ret)
                );
                return ret;
            }
    
            // write the frame data to output file
            if (dec->codec->type == AVMEDIA_TYPE_VIDEO)
                ret = output_video_frame(frame);
            else
                ret = output_audio_frame(frame);
    
            av_frame_unref(frame);
            if (ret < 0)
                return ret;
        }
    
        return 0;
    }
    
    static int open_codec_context(int* stream_idx,
        AVCodecContext** dec_ctx, AVFormatContext* fmt_ctx, enum AVMediaType type)
    {
        int ret, stream_index;
        AVStream* st;
        AVCodec* dec = NULL;
        AVDictionary* opts = NULL;
    
        ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
        if (ret < 0) {
            fprintf(stderr, "Could not find %s stream in input file '%s'\n",
                av_get_media_type_string(type), src_filename);
            return ret;
        }
        else {
            stream_index = ret;
            st = fmt_ctx->streams[stream_index];
    
            /* find decoder for the stream */
            dec = avcodec_find_decoder(st->codecpar->codec_id);
            if (!dec) {
                fprintf(stderr, "Failed to find %s codec\n",
                    av_get_media_type_string(type));
                return AVERROR(EINVAL);
            }
    
            /* Allocate a codec context for the decoder */
            *dec_ctx = avcodec_alloc_context3(dec);
            if (!*dec_ctx) {
                fprintf(stderr, "Failed to allocate the %s codec context\n",
                    av_get_media_type_string(type));
                return AVERROR(ENOMEM);
            }
    
            /* Copy codec parameters from input stream to output codec context */
            if ((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) {
                fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
                    av_get_media_type_string(type));
                return ret;
            }
    
            /* Init the decoders */
            if ((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) {
                fprintf(stderr, "Failed to open %s codec\n",
                    av_get_media_type_string(type));
                return ret;
            }
            *stream_idx = stream_index;
        }
    
        return 0;
    }
    
    static int get_format_from_sample_fmt(const char** fmt,
        enum AVSampleFormat sample_fmt)
    {
        int i;
        struct sample_fmt_entry {
            enum AVSampleFormat sample_fmt; const char* fmt_be, * fmt_le;
        } sample_fmt_entries[] = {
            { AV_SAMPLE_FMT_U8,  "u8",    "u8"    },
            { AV_SAMPLE_FMT_S16, "s16be", "s16le" },
            { AV_SAMPLE_FMT_S32, "s32be", "s32le" },
            { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
            { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
        };
        *fmt = NULL;
    
        for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
            struct sample_fmt_entry* entry = &sample_fmt_entries[i];
            if (sample_fmt == entry->sample_fmt) {
                *fmt = AV_NE(entry->fmt_be, entry->fmt_le);
                return 0;
            }
        }
    
        fprintf(stderr,
            "sample format %s is not supported as output format\n",
            av_get_sample_fmt_name(sample_fmt));
        return -1;
    }
    
    int main1(int argc, char** argv)
    {
        int ret = 0;
        int n_channels =0;
        sdlRender = std::make_shared<CGSDLRender>();
        /*
        if (argc != 4) {
            fprintf(stderr, "usage: %s  input_file video_output_file audio_output_file\n"
                "API example program to show how to read frames from an input file.\n"
                "This program reads frames from a file, decodes them, and writes decoded\n"
                "video frames to a rawvideo file named video_output_file, and decoded\n"
                "audio frames to a rawaudio file named audio_output_file.\n",
                argv[0]);
            exit(1);
        }
        src_filename = argv[1];
        video_dst_filename = argv[2];
        audio_dst_filename = argv[3];
        */
        //src_filename = "test.mp4";
        src_filename = argv[1];
       //   src_filename = "sax.mp3";
        //video_dst_filename = "del.yuv";
          audio_dst_filename = "del.pcm";
    
        /* open input file, and allocate format context */
        if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
            fprintf(stderr, "Could not open source file %s\n", src_filename);
            exit(1);
        }
    
        /* retrieve stream information */
        if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
            fprintf(stderr, "Could not find stream information\n");
            exit(1);
        }
    
        if (open_codec_context(&video_stream_idx, &video_dec_ctx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) {
            video_stream = fmt_ctx->streams[video_stream_idx];
            /*
            video_dst_file = fopen(video_dst_filename, "wb");
            if (!video_dst_file) {
                fprintf(stderr, "Could not open destination file %s\n", video_dst_filename);
                ret = 1;
                goto end;
            }
            */
            /* allocate image where the decoded image will be put */
            width = video_dec_ctx->width;
            height = video_dec_ctx->height;
            pix_fmt = video_dec_ctx->pix_fmt;
            ret = av_image_alloc(video_dst_data, video_dst_linesize,
                width, height, pix_fmt, 1);
            if (ret < 0) {
                fprintf(stderr, "Could not allocate raw video buffer\n");
                goto end;
            }
            video_dst_bufsize = ret;
    
            
            sdlRender->InitVideo(0);
            sdlRender->CreateVideoSurface(width, height);
    
            refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL);
        }
    
    
        if (open_codec_context(&audio_stream_idx, &audio_dec_ctx, fmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0) {
            audio_stream = fmt_ctx->streams[audio_stream_idx];
            /*
            audio_dst_file = fopen(audio_dst_filename, "wb");
            if (!audio_dst_file) {
                fprintf(stderr, "Could not open destination file %s\n", audio_dst_filename);
                ret = 1;
                goto end;
            }*/
            n_channels = audio_dec_ctx->channels;
            printf("init rate,chan %d %d--------->\n", audio_dec_ctx->sample_rate, n_channels);
            sdlRender->InitAudio(audio_dec_ctx->sample_rate, n_channels);
    
            //--
            if (audio_dec_ctx->sample_fmt != AV_SAMPLE_FMT_S16)
            {
                swr = swr_alloc();
                av_opt_set_int(swr, "in_channel_layout", audio_dec_ctx->channel_layout, 0);
                av_opt_set_int(swr, "out_channel_layout", audio_dec_ctx->channel_layout, 0);
                av_opt_set_int(swr, "in_sample_rate", audio_dec_ctx->sample_rate, 0);
                av_opt_set_int(swr, "out_sample_rate", audio_dec_ctx->sample_rate, 0);
                av_opt_set_sample_fmt(swr, "in_sample_fmt", audio_dec_ctx->sample_fmt, 0);
                av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
                swr_init(swr);
            }
            //--
        }
    
        /* dump input information to stderr */
        av_dump_format(fmt_ctx, 0, src_filename, 0);
    
        if (!audio_stream && !video_stream) {
            fprintf(stderr, "Could not find audio or video stream in the input, aborting\n");
            ret = 1;
            goto end;
        }
    
        frame = av_frame_alloc();
        if (!frame) {
            fprintf(stderr, "Could not allocate frame\n");
            ret = AVERROR(ENOMEM);
            goto end;
        }
    
        pkt = av_packet_alloc();
        if (!pkt) {
            fprintf(stderr, "Could not allocate packet\n");
            ret = AVERROR(ENOMEM);
            goto end;
        }
    
        if (video_stream)
            printf("Demuxing video from file '%s' into '%s'\n", src_filename, video_dst_filename);
        if (audio_stream)
            printf("Demuxing audio from file '%s' into '%s'\n", src_filename, audio_dst_filename);
    
        /* read frames from the file */
        while (av_read_frame(fmt_ctx, pkt) >= 0) {
            // check if the packet belongs to a stream we are interested in, otherwise
            // skip it
            if (pkt->stream_index == video_stream_idx)
                ret = decode_packet(video_dec_ctx, pkt);
            else if (pkt->stream_index == audio_stream_idx)
                ret = decode_packet(audio_dec_ctx, pkt);
            av_packet_unref(pkt);
            if (ret < 0)
                break;
        }
    
        /* flush the decoders */
        if (video_dec_ctx)
            decode_packet(video_dec_ctx, NULL);
        if (audio_dec_ctx)
            decode_packet(audio_dec_ctx, NULL);
    
        printf("Demuxing succeeded.\n");
    
        if (video_stream) {
            printf("Play the output video file with the command:\n"
                "ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
                av_get_pix_fmt_name(pix_fmt), width, height,
                "");
        }
    
        if (audio_stream) {
            enum AVSampleFormat sfmt = audio_dec_ctx->sample_fmt;
            int n_channels = audio_dec_ctx->channels;
            const char* fmt;
    
            if (av_sample_fmt_is_planar(sfmt)) {
                const char* packed = av_get_sample_fmt_name(sfmt);
                printf("Warning: the sample format the decoder produced is planar "
                    "(%s). This example will output the first channel only.\n",
                    packed ? packed : "?");
                sfmt = av_get_packed_sample_fmt(sfmt);
                n_channels = 1;
            }
           
            if ((ret = get_format_from_sample_fmt(&fmt, sfmt)) < 0)
                goto end;
    
            printf("Play the output audio file with the command:\n"
                "ffplay -f %s -ac %d -ar %d %s\n",
                fmt, n_channels, audio_dec_ctx->sample_rate,
                "");
    
           
        }
    
    end:
        avcodec_free_context(&video_dec_ctx);
        avcodec_free_context(&audio_dec_ctx);
        avformat_close_input(&fmt_ctx);
         /*
        if (video_dst_file)
            fclose(video_dst_file);  
       if (audio_dst_file)
            fclose(audio_dst_file);
      */
        av_packet_free(&pkt);
        av_frame_free(&frame);
        av_free(video_dst_data[0]);
    
        return ret < 0;
    }
  • 相关阅读:
    【原】结构体包含CString类型成员变量出错的原理
    Android View移动的六种方法
    Android开发之getX,getRawX,getWidth,getTranslationX等的区别
    Android 自定义漂亮的圆形进度条
    android studio 如何让包名展开
    Android基础之——CountDownTimer类,轻松实现倒计时功能
    Java/Android倒计时(开始,暂停,恢复,停止)
    Android Studio:正确导入SO相关文件
    Android MediaPlayer和VideoView的使用
    android studio 将自己的项目生成jar包
  • 原文地址:https://www.cnblogs.com/cnchengv/p/15750389.html
Copyright © 2020-2023  润新知