美文网首页
ffmpeg+sdl解码h264数据流程

ffmpeg+sdl解码h264数据流程

作者: jeffleefree | 来源:发表于2016-04-14 20:00 被阅读694次

    我在分析网上大神的博客后使用ffmpeg + sdl 成功地播放了h264数据,所以做了下面的记录.

    解码h264数据为yuv240p

    ffmpeg 头文件
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libswscale/swscale.h"
    
        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;
    

    创建这些变量,结构体

        //注册ffmpeg编解码器
        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"); //打开h264文件
            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;
        }
    
        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);//转码的信息
    
    while (av_read_frame(pFormatCtx, packet) >= 0) {
            if (packet->stream_index == videoindex) {
                ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
                if (ret < 0) {
                    printf("Decode Error.\n");
                    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);//转码一帧数据
    

    SDL

    初始化SDL

    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
            printf("Could not initialize SDL - %s\n", 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\n", 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;
    
    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 End-----------------------
                    //Delay 40ms
                    SDL_Delay(40);
    
     //最后将所有的资源释放掉
    SDL_Quit();
    
        av_frame_free(&pFrameYUV);
        av_frame_free(&pFrame);
        avcodec_close(pCodecCtx);
        avformat_close_input(&pFormatCtx);
    

    tips

    在编译完成后,我点击运行,没有什么反应,但是我点击生成的exe却可以执行
    当时我觉得很奇怪,在试错之后明白了,是filepath[]的问题,编译的是cpp的路径,
    执行的exe在Debug下面,它们不一样.
    感觉这是不人性化的设置

    相关文章

      网友评论

          本文标题:ffmpeg+sdl解码h264数据流程

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