zoukankan      html  css  js  c++  java
  • 简单播放器(增加sdl事件控制)

    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
    #include <stdio.h>
    #include <SDL2/SDL.h>
    #include <time.h>
    
    #define SFM_REFRESH_EVENT  (SDL_USEREVENT + 1)
    
    int thread_exit=0;
    //Thread
    int sfp_refresh_thread(void *opaque)
    {
        SDL_Event event;
        while (thread_exit==0) {
            event.type = SFM_REFRESH_EVENT;
            SDL_PushEvent(&event);
            //Wait 40 ms
            SDL_Delay(15);
        }
        return 0;
    }
    
    int main(int argc, char* argv[])
    {
        AVFormatContext    *pFormatCtx;//格式上下文结构体
        int                i, videoindex;
        AVCodecContext    *pCodecCtx;//codec上下文
        AVCodec            *pCodec;//codec
        
        int screen_w=0,screen_h=0;  
        SDL_Window *screen;   
        SDL_Renderer* sdlRenderer;  
        SDL_Texture* sdlTexture;  
        SDL_Rect sdlRect;
        SDL_Thread *video_tid;
        SDL_Event event;
        
        av_register_all();//ffmpeg flow 0,注册codec
        avformat_network_init();//如要打开网络流,必须运行此函数
        pFormatCtx = avformat_alloc_context();//格式上下文结构体指针开空间
        if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)//打开多媒体文件
        {
            printf("open file error
    ");
            return -1;
        }
    
        AVDictionary* pOptions = NULL;
        if ( avformat_find_stream_info(pFormatCtx, &pOptions) < 0 )//读取音视频数据相关信息,参数0:上下文结构体指针,参数1:option  
        {
            return -1;
        }
        av_dump_format(pFormatCtx, 0, argv[1], 0);//调试函数,输出文件的音、视频流的基本信息
    
        //获取视频的时长
        if(pFormatCtx->duration != AV_NOPTS_VALUE)
        {  
            int hours, mins, secs, us;  
            int64_t duration = pFormatCtx->duration + 5000;  
            secs = duration / AV_TIME_BASE;  
            us = duration % AV_TIME_BASE;  
            mins = secs / 60;  
            secs %= 60;  
            hours = mins/ 60;  
            mins %= 60;  
            printf("%02d:%02d:%02d.%02d
    ", hours, mins, secs, (100 * us) / AV_TIME_BASE);  
        } 
    
    
    
        i = 0;
        int videostream = -1;
        printf("pFormatCtx->nb_streams=%d
    ", pFormatCtx->nb_streams);
        for(i=0;i<pFormatCtx->nb_streams;i++)//遍历多媒体文件中的每一个流,判断是否为视频。
        {
            if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
            {
                videostream = i;
                break;
            }
        }
        printf("videostream=%d
    ", videostream);
        
        if (-1 == videostream)
        {
            printf("error no video stream
    ");
            return;
        }
    
        pCodecCtx = pFormatCtx->streams[videostream]->codec;//codec上下文指定到格式上下文中的codec
    
        
        pCodec = avcodec_find_decoder( pCodecCtx->codec_id );//找到一个codec,必须先调用av_register_all()
        
        if(NULL == pCodec)
        {
            printf("couldn't find the decode
    ");
            return -1;
        }
        
        if( avcodec_open2(pCodecCtx, pCodec, NULL) < 0)//初始化一个视音频编解码器的AVCodecContext
        {
            printf("open decode error
    ");
            return -1;
        }
    
        AVFrame    *pFrame,*pFrameYUV;//Frame结构体
        pFrame = av_frame_alloc();//原始帧
        pFrameYUV = av_frame_alloc();//YUV帧
        uint8_t *out_buffer;
    
        int num = avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
        printf("num=%d
    ", num);
    
    
        out_buffer = (uint8_t *)av_malloc(num*sizeof(uint8_t));
        avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);//将pFrameYUV和out_buffer联系起来(pFrame指向一段内存)
    
    
        AVPacket packet;//packet结构体
        int ret = -1;
        i = 0;
        struct SwsContext *img_convert_ctx = NULL;//图像格式转化上下文 
        img_convert_ctx = sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt , pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);//初始化SWS,图片格式转化上下文
        
        if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) 
        {    
            printf( "Could not initialize SDL - %s
    ", SDL_GetError());   
            return -1;  
        }
        
        screen_w = pCodecCtx->width;  
        screen_h = pCodecCtx->height;  
        //SDL 2.0 Support for multiple windows  
        screen = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,  
            screen_w, screen_h,  
            SDL_WINDOW_OPENGL);
    
      
        if(!screen) 
        {    
            printf("SDL: could not create window - exiting:%s
    ",SDL_GetError());    
            return -1;  
        }
        
        sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
        sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,pCodecCtx->width,pCodecCtx->height);    
        sdlRect.x=0;  
        sdlRect.y=0;  
        sdlRect.w=screen_w;  
        sdlRect.h=screen_h;
        
        int f1 = 0;
        int f2 = 0;
        int got_picture = -1;
    
        video_tid = SDL_CreateThread(sfp_refresh_thread,NULL,NULL);
        time_t t;
        time(&t);
        printf("begin :%s
    ", ctime(&t));
    
        while (1) 
        {
            SDL_WaitEvent(&event);
            if(event.type==SFM_REFRESH_EVENT)
            {
                if(av_read_frame(pFormatCtx, &packet)>=0)//读取码流中的音频若干帧或者视频一帧,作为packet
                {
                    f1++;
                    if(packet.stream_index == videostream)//如果是视频
                    {
                        ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);//解码一帧视频数据。输入一个压缩编码的结构体AVPacket,输出一个解码后的结构体AVFrame
            
                        if(ret < 0)
                        {
                            printf("decode error
    ");
                            return -1;
                        }
                
                        if(got_picture)
                        {
                                //转换
                            sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 
                                        0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);//将输出结果转化成YUV
                    
                            SDL_UpdateYUVTexture(sdlTexture, &sdlRect,  
                            pFrameYUV->data[0], pFrameYUV->linesize[0],  
                            pFrameYUV->data[1], pFrameYUV->linesize[1],  
                            pFrameYUV->data[2], pFrameYUV->linesize[2]);  
                    
                            SDL_RenderClear( sdlRenderer );    
                            SDL_RenderCopy( sdlRenderer, sdlTexture,  NULL, &sdlRect);   
                            SDL_RenderPresent( sdlRenderer );
                    
                            //SDL_Delay(40);
    
                            f2++;
    
                        }
                    }             
    
                    av_free_packet(&packet);
                }
                else
                {
                    thread_exit=1;
                    break;
                }
            }
    
        }
    
        time(&t);
        printf("begin :%s
    ", ctime(&t));
    
        SDL_Quit();
    
        sws_freeContext(img_convert_ctx);
    
         free(out_buffer);
        av_free(pFrameYUV);
    
        // Free the YUV frame
        av_free(pFrame);
    
        // Close the codec
        avcodec_close(pCodecCtx);
    
        // Close the video file
        avformat_close_input(&pFormatCtx);
    
        printf("f1=%d
    ", f1);
        printf("f2=%d
    ", f2);
    
        return 0;
    }
  • 相关阅读:
    第一篇阅读笔记
    课程信息管理系统
    HDU1124求n的阶乘后0的个数
    分解质因数算法
    牛客小白月赛23 B阶乘(质因数分解)
    JAVAWEB将图片铺满整个页面的方法
    Codeforces Global Round 7
    POJ--1703并查集(区分两个集合)
    POJ--1611经典并查集
    DFS,BFS回顾(各种题)(肺炎疫情中,祝平安)
  • 原文地址:https://www.cnblogs.com/zhangxuan/p/6047742.html
Copyright © 2011-2022 走看看