SDL2.0+ffmpeg2.3

看了一篇博文100行代码实现最简单的基于ffmpeg+sdl的视频播放器,地址:http://blog.csdn.net/leixiaohua1020/article/details/8652605,于是乎前面学习了一哈SDL2.0,前两天看了一下ffdoc,感觉API变化了好多,现将新的代码附上:只有最基本的功能,

环境:windows XP

IDE:codeblocks13.12

SDL版本:SDL2.0

ffmpeg版本:ffmpeg2.3

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>
#include <libavutil/mem.h>
#include <libswscale/swscale.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_thread.h>

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define    rmask 0xff000000
#define    gmask 0x00ff0000
#define    bmask 0x0000ff00
#define    amask 0x000000ff
#else
#define    rmask  0x000000ff
#define    gmask  0x0000ff00
#define    bmask  0x00ff0000
#define    amask  0xff000000
#endif

void SaveFrame(AVFrame *pFrame, int width, int height)
{
    FILE *pFile;
    char szFilename[32];
    int y;
    static int iFrame = 0;
    sprintf(szFilename,"frame%d.ppm",iFrame);
    pFile = fopen(szFilename,"wb");
    if(pFile == NULL)
    {
        return;
    }
    //write header
    fprintf(pFile, "P6\n%d %d\n255\n",width,height);
    //write pixel data
    for(y = 0; y < height;y++)
        fwrite(pFrame->data[0] + y*pFrame->linesize[0],1,width*3,pFile);//写入一行数据
    fclose(pFile);
    iFrame++;
}
int main(int argc, char* args[])
{
    av_register_all();
    AVFormatContext* pFormatCtx;

    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        printf("SDL init failed error:%s\n",SDL_GetError());
        return -1;
    }
    pFormatCtx = avformat_alloc_context();
    if(pFormatCtx == NULL)
    {
        printf("couldn't alloc a avformatcontext\n");
        return -1;
    }
    if(avformat_open_input(&pFormatCtx,"123.flv",NULL, NULL) != 0)
    {
        printf("couldn't open file!\n");
        return -1;
    }
    if(avformat_find_stream_info(pFormatCtx,NULL) != 0)
    {
        printf("couldn't find stream information!\n");
        return -1;
    }
    printf("nb_streams:%d\n",pFormatCtx->nb_streams);
    int i = 0,videoStream = -1;
    AVCodecContext* pCodecCtx;
    //一个文件一般有两种流:一个音频流、一个视频流
    for(i = 0; i < pFormatCtx->nb_streams;i++)
        if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoStream = i;
            break;
        }
    if(videoStream == -1)
    {
        printf("couldn't find a video stream!\n");
        return -1;
    }
    //here we find a video stream
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;
    AVCodec* pCodec;
    //find the decoder for the video stream
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec == NULL)
    {
        printf("unsupported codec!\n");
        return -1;
    }
    if(avcodec_open2(pCodecCtx,pCodec,NULL) < 0)
    {
        printf("open the codec failed!\n");
        return -1;
    }
    SDL_Surface *screen = NULL;
    SDL_Window* gWindow = NULL;
    SDL_Surface*surface = NULL;
    gWindow = SDL_CreateWindow( "FFmpeg", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, pCodecCtx->width, pCodecCtx->height, SDL_WINDOW_SHOWN );
    if(gWindow == NULL)
    {
        printf("create window failed:%s",SDL_GetError());
        return -1;
    }
    screen = SDL_GetWindowSurface(gWindow);
    if(screen == NULL)
    {
         printf("create surface failed:%s",SDL_GetError());
        return -1;
    }
    SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format,0xff,0xff,0xff));
    AVFrame* pFrame,*pFrameRGB;//用于保存一个帧(保存成24位RGB色的PPM文件,需要格式转换,将原始的帧切换成特定格式的帧)
    pFrame = av_frame_alloc();//为帧申请一块内存
    pFrameRGB = av_frame_alloc();//为帧申请一块内存
    if(pFrameRGB == NULL)
    {
        printf("alloc rgb frame failed!\n");
        return -1;
    }

    uint8_t *buffer;
    int numBytes;
    numBytes = avpicture_get_size(AV_PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);//转成rgb24需要的帧大小
    buffer = (uint8_t*)av_malloc(numBytes*sizeof(uint8_t));//为rgb24帧申请空间,buffer为起始地址

    avpicture_fill((AVPicture*)pFrameRGB,buffer,AV_PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);

    //把申请的内存和rgb24帧结合起来,准备读取数据
    int frameFinished,ret;
    AVPacket packet;
    struct SwsContext *pSwsCtx;
    pSwsCtx = sws_getCachedContext(NULL,pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,
                             AV_PIX_FMT_RGB24,SWS_BILINEAR,NULL,NULL,NULL);
    if(pSwsCtx == NULL)
    {
        printf("get sws context failed!\n");
        return -1;
    }


    while(av_read_frame(pFormatCtx, &packet)>=0) //读取一个包并保存到packet中
    {
        // Is this a packet from the video stream?
        if(packet.stream_index==videoStream)
        {
            // Decode video frame
            ret = avcodec_decode_video2(pCodecCtx, pFrame,&frameFinished, &packet);
            if(ret < 0)
            {
                printf("Decode failed!\n");
                return -1;
            }

            // Did we get a video frame?
            if(frameFinished)
            {
                sws_scale(pSwsCtx,
                        (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
                       pFrameRGB->data, pFrameRGB->linesize);
                 //Save the frame to disk
                 surface = SDL_CreateRGBSurfaceFrom(pFrameRGB->data[0],pCodecCtx->width,pCodecCtx->height,24,pCodecCtx->width*3,
                                                    rmask,gmask,bmask,amask);
                 SDL_BlitSurface(surface,NULL,screen,NULL);
                 SDL_UpdateWindowSurface(gWindow);
                 SDL_Delay(50);
                //SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height);
            }
        }
        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
    }

    // Free the RGB image
    av_free(buffer);
    av_free(pFrameRGB);
    sws_freeContext(pSwsCtx);
    SDL_FreeSurface(surface);
    surface = NULL;
    SDL_DestroyWindow(gWindow);
    gWindow = NULL;
    SDL_Quit();
    // Free the YUV frame
    av_free(pFrame);

    // Close the codec
    avcodec_close(pCodecCtx);

    // Close the video file
    avformat_close_input(&pFormatCtx);
    return 0;
}

结果:


SDL教程:http://lazyfoo.net/tutorials/SDL/index.php,最近很难打开了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值