zoukankan      html  css  js  c++  java
  • 基于FFmpeg的视频播放器

    转载自雷神博客: https://blog.csdn.net/leixiaohua1020/article/details/38868499

    /**
     * 最简单的基于FFmpeg的视频播放器2(SDL升级版)
     * Simplest FFmpeg Player 2(SDL Update)
     *
     * 雷霄骅 Lei Xiaohua
     * leixiaohua1020@126.com
     * 中国传媒大学/数字电视技术
     * Communication University of China / Digital TV Technology
     * http://blog.csdn.net/leixiaohua1020
     *
     * 第2版使用SDL2.0取代了第一版中的SDL1.2
     * Version 2 use SDL 2.0 instead of SDL 1.2 in version 1.
     *
     * 本程序实现了视频文件的解码和显示(支持HEVC,H.264,MPEG2等)。
     * 是最简单的FFmpeg视频解码方面的教程。
     * 通过学习本例子可以了解FFmpeg的解码流程。
     * 本版本中使用SDL消息机制刷新视频画面。
     * This software is a simplest video player based on FFmpeg.
     * Suitable for beginner of FFmpeg.
     *
     * 备注:
     * 标准版在播放视频的时候,画面显示使用延时40ms的方式。这么做有两个后果:
     * (1)SDL弹出的窗口无法移动,一直显示是忙碌状态
     * (2)画面显示并不是严格的40ms一帧,因为还没有考虑解码的时间。
     * SU(SDL Update)版在视频解码的过程中,不再使用延时40ms的方式,而是创建了
     * 一个线程,每隔40ms发送一个自定义的消息,告知主函数进行解码显示。这样做之后:
     * (1)SDL弹出的窗口可以移动了
     * (2)画面显示是严格的40ms一帧
     * Remark:
     * Standard Version use's SDL_Delay() to control video's frame rate, it has 2
     * disadvantages:
     * (1)SDL's Screen can't be moved and always "Busy".
     * (2)Frame rate can't be accurate because it doesn't consider the time consumed 
     * by avcodec_decode_video2()
     * SU(SDL Update)Version solved 2 problems above. It create a thread to send SDL 
     * Event every 40ms to tell the main loop to decode and show video frames.
     */
     
    #include <stdio.h>
     
    #define __STDC_CONSTANT_MACROS
     
    #ifdef _WIN32
    //Windows
    extern "C"
    {
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libswscale/swscale.h"
    #include "libavutil/imgutils.h"
    #include "SDL2/SDL.h"
    };
    #else
    //Linux...
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
    #include <libavutil/imgutils.h>
    #include <SDL2/SDL.h>
    #ifdef __cplusplus
    };
    #endif
    #endif
     
    //Refresh Event
    #define SFM_REFRESH_EVENT  (SDL_USEREVENT + 1)
     
    #define SFM_BREAK_EVENT  (SDL_USEREVENT + 2)
     
    int thread_exit=0;
    int thread_pause=0;
     
    int sfp_refresh_thread(void *opaque){
        thread_exit=0;
        thread_pause=0;
     
        while (!thread_exit) {
            if(!thread_pause){
                SDL_Event event;
                event.type = SFM_REFRESH_EVENT;
                SDL_PushEvent(&event);
            }
            SDL_Delay(40);
        }
        thread_exit=0;
        thread_pause=0;
        //Break
        SDL_Event event;
        event.type = SFM_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;
        unsigned char *out_buffer;
        AVPacket *packet;
        int ret, got_picture;
     
        //------------SDL----------------
        int screen_w,screen_h;
        SDL_Window *screen; 
        SDL_Renderer* sdlRenderer;
        SDL_Texture* sdlTexture;
        SDL_Rect sdlRect;
        SDL_Thread *video_tid;
        SDL_Event event;
     
        struct SwsContext *img_convert_ctx;
     
        //char filepath[]="bigbuckbunny_480x272.h265";
        char filepath[]="Titanic.ts";
     
        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.
    ");
            return -1;
        }
        if(avformat_find_stream_info(pFormatCtx,NULL)<0){
            printf("Couldn't find stream information.
    ");
            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.
    ");
    
            return -1;
        }
        pCodecCtx=pFormatCtx->streams[videoindex]->codec;
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
        if(pCodec==NULL){
            printf("Codec not found.
    ");
            return -1;
        }
        if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){
            printf("Could not open codec.
    ");
            return -1;
        }
        pFrame=av_frame_alloc();
        pFrameYUV=av_frame_alloc();
     
        out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P,  pCodecCtx->width, pCodecCtx->height,1));
        av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize,out_buffer,
            AV_PIX_FMT_YUV420P,pCodecCtx->width, pCodecCtx->height,1);
     
        //Output Info-----------------------------
        printf("---------------- File Information ---------------
    ");
        av_dump_format(pFormatCtx,0,filepath,0);
        printf("-------------------------------------------------
    ");
        
        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); 
        
     
        if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
            printf( "Could not initialize SDL - %s
    ", SDL_GetError()); 
            return -1;
        } 
        //SDL 2.0 Support for multiple windows
        screen_w = pCodecCtx->width;
        screen_h = pCodecCtx->height;
        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);  
        //IYUV: Y + U + V  (3 planes)
        //YV12: Y + V + U  (3 planes)
        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;
     
        packet=(AVPacket *)av_malloc(sizeof(AVPacket));
     
        video_tid = SDL_CreateThread(sfp_refresh_thread,NULL,NULL);
        //------------SDL End------------
        //Event Loop
        
        for (;;) {
            //Wait
            SDL_WaitEvent(&event);
            if(event.type==SFM_REFRESH_EVENT){
                while(1){
                    if(av_read_frame(pFormatCtx, packet)<0)
                        thread_exit=1;
     
                    if(packet->stream_index==videoindex)
                        break;
                }
                ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
                if(ret < 0){
                    printf("Decode Error.
    ");
                    return -1;
                }
                if(got_picture){
                    sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
                    //SDL---------------------------
                    SDL_UpdateTexture( sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0] );  
                    SDL_RenderClear( sdlRenderer );  
                    //SDL_RenderCopy( sdlRenderer, sdlTexture, &sdlRect, &sdlRect );  
                    SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, NULL);  
                    SDL_RenderPresent( sdlRenderer );  
                    //SDL End-----------------------
                }
                av_free_packet(packet);
            }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==SFM_BREAK_EVENT){
                break;
            }
     
        }
     
        sws_freeContext(img_convert_ctx);
     
        SDL_Quit();
        //--------------
        av_frame_free(&pFrameYUV);
        av_frame_free(&pFrame);
        avcodec_close(pCodecCtx);
        avformat_close_input(&pFormatCtx);
     
        return 0;
    }
  • 相关阅读:
    Java学习笔记12---向上转型-父类的对象引用指向子类对象
    Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序
    Java学习笔记10---访问权限修饰符如何控制成员变量、成员方法及类的访问范围
    Java学习笔记9---类静态成员变量的存储位置及JVM的内存划分
    Java学习笔记8---类的静态成员变量与静态成员方法的访问与调用方式
    Java学习笔记7---父类构造方法有无参数对子类的影响
    Java学习笔记6---字符串比较方法compareTo(String str)
    地址总线、数据总线、寻址能力、字长及cpu位数等概念之间的关系
    Alpha事后诸葛亮
    第05组 Alpha冲刺(4/4)
  • 原文地址:https://www.cnblogs.com/nanqiang/p/13683324.html
Copyright © 2011-2022 走看看