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

FFmpeg+SDL(雷神)-(6)

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

    (6) FFmpeg+SDL视频播放器-图形界面版
    代码记录


    // testplayermfcDlg.cpp : 实现文件
    //
    
    #include "stdafx.h"
    #include "testplayermfc.h"
    #include "testplayermfcDlg.h"
    #include "afxdialogex.h"
    
    #define __STDC_CONSTANT_MACROS
    
    extern "C"
    {
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libswscale/swscale.h"
    #include "sdl/SDL.h"
    }
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
    
    class CAboutDlg : public CDialogEx
    {
    public:
        CAboutDlg();
    
    // 对话框数据
        enum { IDD = IDD_ABOUTBOX };
    
        protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    
    // 实现
    protected:
        DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
    {
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
        CDialogEx::DoDataExchange(pDX);
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
    END_MESSAGE_MAP()
    
    
    // CtestplayermfcDlg 对话框
    
    
    
    
    CtestplayermfcDlg::CtestplayermfcDlg(CWnd* pParent /*=NULL*/)
        : CDialogEx(CtestplayermfcDlg::IDD, pParent)
    {
        m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CtestplayermfcDlg::DoDataExchange(CDataExchange* pDX)
    {
        CDialogEx::DoDataExchange(pDX);
        DDX_Control(pDX, IDC_URL, m_url);
    }
    
    BEGIN_MESSAGE_MAP(CtestplayermfcDlg, CDialogEx)
        ON_WM_SYSCOMMAND()
        ON_WM_PAINT()
        ON_WM_QUERYDRAGICON()
        ON_BN_CLICKED(IDC_PLAY, &CtestplayermfcDlg::OnBnClickedPlay)
        ON_BN_CLICKED(IDC_PAUSE, &CtestplayermfcDlg::OnBnClickedPause)
        ON_BN_CLICKED(IDC_STOP, &CtestplayermfcDlg::OnBnClickedStop)
        ON_BN_CLICKED(IDC_ABOUT, &CtestplayermfcDlg::OnBnClickedAbout)
        ON_BN_CLICKED(IDC_FILEDIALOG, &CtestplayermfcDlg::OnBnClickedFiledialog)
    END_MESSAGE_MAP()
    
    
    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;
    }
    
    UINT ffmpegplayer(LPVOID lpParam)
    {
        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;
    
        //输入文件路径
        CtestplayermfcDlg *dlg=(CtestplayermfcDlg *)lpParam;
        //------------------------
        char filepath[500]={0};
        GetWindowTextA(dlg->m_url,(LPSTR)filepath,500);
        //------------------------
        //char filepath[]="Titanic.ts";
    
        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; 
        //SDL 2.0 Support for multiple windows
        screen_w=pCodecCtx->width;
        screen_h=pCodecCtx->height;
        //screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        //  screen_w, screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
    
        screen = SDL_CreateWindowFrom(dlg->GetDlgItem(IDC_SCREEN)->GetSafeHwnd());
        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, NULL);  
                    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);
    
        SDL_Quit();
        
        dlg->GetDlgItem(IDC_SCREEN)->ShowWindow(SW_SHOWNORMAL);
    
        //------------
        av_frame_free(&pFrameYUV);
        av_frame_free(&pFrame);
        avcodec_close(pCodecCtx);//关闭解码器
        avformat_close_input(&pFormatCtx);//关闭输入视频文件
        
        return 0;
    }
    
    
    // CtestplayermfcDlg 消息处理程序
    
    BOOL CtestplayermfcDlg::OnInitDialog()
    {
        CDialogEx::OnInitDialog();
    
        // 将“关于...”菜单项添加到系统菜单中。
    
        // IDM_ABOUTBOX 必须在系统命令范围内。
        ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
        ASSERT(IDM_ABOUTBOX < 0xF000);
    
        CMenu* pSysMenu = GetSystemMenu(FALSE);
        if (pSysMenu != NULL)
        {
            BOOL bNameValid;
            CString strAboutMenu;
            bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
            ASSERT(bNameValid);
            if (!strAboutMenu.IsEmpty())
            {
                pSysMenu->AppendMenu(MF_SEPARATOR);
                pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
            }
        }
    
        // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
        //  执行此操作
        SetIcon(m_hIcon, TRUE);         // 设置大图标
        SetIcon(m_hIcon, FALSE);        // 设置小图标
    
        // TODO: 在此添加额外的初始化代码
    
        return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
    }
    
    void CtestplayermfcDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
        if ((nID & 0xFFF0) == IDM_ABOUTBOX)
        {
            CAboutDlg dlgAbout;
            dlgAbout.DoModal();
        }
        else
        {
            CDialogEx::OnSysCommand(nID, lParam);
        }
    }
    
    // 如果向对话框添加最小化按钮,则需要下面的代码
    //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
    //  这将由框架自动完成。
    
    void CtestplayermfcDlg::OnPaint()
    {
        if (IsIconic())
        {
            CPaintDC dc(this); // 用于绘制的设备上下文
    
            SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    
            // 使图标在工作区矩形中居中
            int cxIcon = GetSystemMetrics(SM_CXICON);
            int cyIcon = GetSystemMetrics(SM_CYICON);
            CRect rect;
            GetClientRect(&rect);
            int x = (rect.Width() - cxIcon + 1) / 2;
            int y = (rect.Height() - cyIcon + 1) / 2;
    
            // 绘制图标
            dc.DrawIcon(x, y, m_hIcon);
        }
        else
        {
            CDialogEx::OnPaint();
        }
    }
    
    //当用户拖动最小化窗口时系统调用此函数取得光标
    //显示。
    HCURSOR CtestplayermfcDlg::OnQueryDragIcon()
    {
        return static_cast<HCURSOR>(m_hIcon);
    }
    
    
    
    void CtestplayermfcDlg::OnBnClickedPlay()
    {
        CString str1;
        m_url.GetWindowText(str1);
        if(str1.IsEmpty()){
            AfxMessageBox("请输入文件路径!");
            return;
        }
        AfxBeginThread(ffmpegplayer,this);//开启线程
    }
    
    
    void CtestplayermfcDlg::OnBnClickedPause()
    {
        thread_pause=!thread_pause;
    }
    
    
    void CtestplayermfcDlg::OnBnClickedStop()
    {
        thread_exit=1;
    }
    
    
    void CtestplayermfcDlg::OnBnClickedAbout()
    {
        CAboutDlg dlg1;
        dlg1.DoModal();
    }
    
    
    void CtestplayermfcDlg::OnBnClickedFiledialog()
    {
        //CString str1;
        //m_url.GetWindowText(str1);
        //str1.Format("%s",avcodec_configuration());
        //AfxMessageBox(str1);
        CString FilePathName;
        CFileDialog dlg(TRUE,NULL,NULL,NULL,NULL);
        if(dlg.DoModal()==IDOK) {
            FilePathName=dlg.GetPathName();
            m_url.SetWindowTextA(FilePathName);
        }
    }
    

    dlg

    相关文章

      网友评论

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

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