美文网首页
FFmpeg+SDL(雷神)-(5-2)

FFmpeg+SDL(雷神)-(5-2)

作者: Goning | 来源:发表于2019-01-08 17:20 被阅读8次

    (5) FFmpeg+SDL视频播放器
    代码记录


    #include "stdafx.h"
    
    #define __STDC_CONSTANT_MACROS
    
    extern "C"
    {
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libswscale/swscale.h"
    #include "sdl/SDL.h"
    }
    
    int screen_w,screen_h;
    
    //Refresh Event
    #define REFRESH_EVENT  (SDL_USEREVENT + 1)
    //Break
    #define BREAK_EVENT  (SDL_USEREVENT + 2)
    
    int thread_exit=0;
    int thread_pause=0;
    
    int refresh_video(void *opaque){
        thread_exit=0;
        while (thread_exit==0) {
            if(thread_pause==0){
            SDL_Event event;
            event.type = REFRESH_EVENT;
            SDL_PushEvent(&event);
            }
            SDL_Delay(40);
        }
        thread_exit=0;
        //Break
        SDL_Event event;
        event.type = BREAK_EVENT;
        SDL_PushEvent(&event);
        return 0;
    }
    
    
    
    int main(int argc, char* argv[])
    {
        AVFormatContext *pFormatCtx;
        int             i, videoindex;
        AVCodecContext  *pCodecCtx;
        AVCodec         *pCodec;
        AVFrame *pFrame,*pFrameYUV;
        uint8_t *out_buffer;
        AVPacket *packet;
        int y_size;
        int ret, got_picture;
        struct SwsContext *img_convert_ctx;
        //输入文件路径
        //char filepath[]="屌丝男士.mov";
        //char filepath[]="Titanic.ts";
        //char filepath[500]={0};
        //strcpy(filepath,argv[1]);
    
        char *filepath=argv[1];
    
        int frame_cnt;
    
        av_register_all();//注册所有组件
        avformat_network_init();
        pFormatCtx = avformat_alloc_context();
    
        if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){//打开输入视频文件
            printf("Couldn't open input stream.\n");
            return -1;
        }
        if(avformat_find_stream_info(pFormatCtx,NULL)<0){//获取视频文件信息
            printf("Couldn't find stream information.\n");
            return -1;
        }
        videoindex=-1;
        for(i=0; i<pFormatCtx->nb_streams; i++) 
            if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
                videoindex=i;
                break;
            }
        if(videoindex==-1){
            printf("Didn't find a video stream.\n");
            return -1;
        }
    
        pCodecCtx=pFormatCtx->streams[videoindex]->codec;
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);//查找解码器
        if(pCodec==NULL){
            printf("Codec not found.\n");
            return -1;
        }
        if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){//打开解码器
            printf("Could not open codec.\n");
            return -1;
        }
    
        pFrame=av_frame_alloc();
        pFrameYUV=av_frame_alloc();
        out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
        avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
        packet=(AVPacket *)av_malloc(sizeof(AVPacket));
        //Output Info-----------------------------
        printf("--------------- File Information ----------------\n");
        av_dump_format(pFormatCtx,0,filepath,0);
        printf("-------------------------------------------------\n");
        img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 
            pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); 
    
        frame_cnt=0;
    
    
        //=======SDL=======
        if(SDL_Init(SDL_INIT_VIDEO)) {  
            printf( "Could not initialize SDL - %s\n", SDL_GetError()); 
            return -1;
        } 
    
        SDL_Window *screen; 
        screen_w=pCodecCtx->width;
        screen_h=pCodecCtx->height;
        //SDL 2.0 Support for multiple windows
        screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
            screen_w, screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
        if(!screen) {  
            printf("SDL: could not create window - exiting:%s\n",SDL_GetError());  
            return -1;
        }
        SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);  
    
        Uint32 pixformat=0;
        //IYUV: Y + U + V  (3 planes)
        //YV12: Y + V + U  (3 planes)
        pixformat= SDL_PIXELFORMAT_IYUV;  
    
        SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pCodecCtx->width,pCodecCtx->height);
    
        SDL_Rect sdlRect;
    
        SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL);
        SDL_Event event;
    
        while(1){
            //Wait
            SDL_WaitEvent(&event);
            if(event.type==REFRESH_EVENT){
                while(1){
                    if(av_read_frame(pFormatCtx, packet)<0)//从输入文件读取一帧压缩数据
                        thread_exit=1;
    
                    if(packet->stream_index==videoindex)//只处理视频帧
                        break;
                }
                /*
                * 在此处添加输出H264码流的代码
                * 取自于packet,使用fwrite()
                */
                ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);//解码一帧压缩数据
                if(ret < 0){
                    printf("Decode Error.\n");
                    return -1;
                }
                if(got_picture){
                    //此处是为了将右边多出来的黑边(硬件导致的)裁剪掉,pFrame->pFrameYUV
                    sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, 
                        pFrameYUV->data, pFrameYUV->linesize);
                    printf("Decoded frame index: %d\n",frame_cnt);
    
                    SDL_UpdateTexture( sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0]);  
                    //FIX: If window is resize
                    sdlRect.x = 0;  
                    sdlRect.y = 0;  
                    sdlRect.w = screen_w;  
                    sdlRect.h = screen_h;  
                    SDL_RenderClear( sdlRenderer );   
                    SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, &sdlRect);  
                    SDL_RenderPresent( sdlRenderer );
    
                    frame_cnt++;
    
                }
                av_free_packet(packet);
            }
            else if(event.type==SDL_WINDOWEVENT){
                //If Resize
                SDL_GetWindowSize(screen,&screen_w,&screen_h);
            }else if(event.type==SDL_KEYDOWN){
                //Pause
                if(event.key.keysym.sym==SDLK_SPACE)
                    thread_pause=!thread_pause;
            }else if(event.type==SDL_QUIT){
                thread_exit=1;
            }else if(event.type==BREAK_EVENT){
                break;
            }
        }
    
        sws_freeContext(img_convert_ctx);
    
        av_frame_free(&pFrameYUV);
        av_frame_free(&pFrame);
        avcodec_close(pCodecCtx);//关闭解码器
        avformat_close_input(&pFormatCtx);//关闭输入视频文件
        
        return 0;
    }
    

    脱离开发环境

    相关文章

      网友评论

          本文标题:FFmpeg+SDL(雷神)-(5-2)

          本文链接:https://www.haomeiwen.com/subject/qfxurqtx.html