ffmpeg简单视频播放器

参考学习雷霄骅的最简单的基于FFMPEG视频播放器。

在移植代码到我的linux环境中时总出现问题,所以干脆把雷神的代码从头到尾分析并移植过来调试。

开发环境:

  操作系统:ubuntu14

  ffmpeg版本:3.2.2

  sdl版本:2

代码我是自己参照雷神的代码敲的,在这过程中,我发现写代码还是要加打印,没有什么能一拿过来就可以成功运行。尤其是在自己设计接口的时候,返回值最好是返回运行结果,需要传出的内存通过参数来传出。

对于错误的判断打印还是需要详细一些,以后在写比较大的程序时要养成加log的习惯,这对调试程序还是有很大帮助的。

下面插入代码:

说明:该程序运行一段时间后会变成黑白,具体原因再查

编译与运行:

gcc -g main.c -o test -I /usr/local/ffmpeg/include -L /usr/local/ffmpeg/lib -lavutil -lavformat -lavcodec -lz -lavutil -lswscale -L /usr/lib/x86_64-linux-gnu -lSDL2 -lSDL2main(其中路径按照自己的安装路径来 -g 是加GDB调试)

./test

  1 #ifdef _cplusplus  2 extern "C"  3 {  4 #endif  5   6 #include<stdio.h>  7 #include<libavcodec/avcodec.h>  8 #include<libavformat/avformat.h>  9 #include<libavutil/avutil.h> 10 #include<libswscale/swscale.h> 11 #include<libavutil/avutil.h> 12 #include<libavutil/imgutils.h> 13 #include<SDL2/SDL.h> 14  15 //是否将YUV420P内容输出到文件 16 #define OUTPUT_YUV420P 0 17 //要播放的文件路径 18 #define filename "/home/sns/cuc_ieschool.flv" 19 //要输出YUV420P内容的文件路径 20 #define outfilename "/home/sns/output.yuv" 21  22 int main(int argc, char **argv) 23 { 24     //变量定义********************************************************************* 25     AVFormatContext *pFormatCtx; 26     int i, videoStream; 27     AVCodecContext *pCodecCtx; 28     AVCodec *pCodec; 29     AVFrame *pFrame; 30     AVFrame *pFrameYUV; 31     uint8_t *buffer; 32     int numBytes; 33  34     SDL_Window *screen; 35     SDL_Renderer *sdlRender; 36     SDL_Texture *sdlTexture; 37     SDL_Rect sdlRect; 38     int frameFinished; 39     AVPacket packet; 40     i = 0; 41     struct SwsContext *img_convert_ctx; 42     int err_code; 43     char buf[1024]; 44     FILE *fp_yuv; 45     int y_size; 46     //******************************************************************************* 47     av_register_all(); 48     //1、打开视频文件************************************************* 49     pFormatCtx = avformat_alloc_context(); 50     err_code = avformat_open_input(&pFormatCtx, filename, NULL, NULL); 51     if (err_code != 0) 52     {//打开文件失败 53         av_strerror(err_code, buf, 1024); 54         printf("coundn't open the file!,error code = %d(%s)\n", err_code, buf); 55         return -1; 56     } 57     if (avformat_find_stream_info(pFormatCtx, NULL) < 0) 58     { 59         printf("Couldn't find stream information.\n"); 60         return -1; 61     } 62     //2、找到第一个视频流**************************** 63     videoStream = -1; 64     for (i = 0; i < pFormatCtx->nb_streams; i++) 65     { 66         if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 67         { 68             videoStream = i;//得到视频流的索引 69             break; 70         } 71     } 72     if (videoStream == -1) 73     { 74         printf("Didn't find a video stream.\n"); 75         return -1; 76     } 77     /* 3、从视频流中得到一个编解码上下文,里面包含了编解码器的所有信息和一个 78     指向真正的编解码器     ,然后我们找到这个解码器*/ 79     pCodecCtx = pFormatCtx->streams[videoStream]->codec; 80     pCodec = avcodec_find_decoder(pCodecCtx->codec_id); 81     if (pCodec == NULL) 82     { 83         fprintf(stderr, "Unsupported codec !\n"); 84         return -1; 85     } 86     //4、打开该编解码器 87     if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) 88     { 89         printf("cann't open the codec!\n"); 90         return -1; 91     } 92     //5、分配两个视频帧,一个保存得到的原始视频帧,一个保存为指定格式的视频帧(该帧通过原始帧转换得来) 93     pFrame = av_frame_alloc(); 94     if (pFrame == NULL) 95     { 96         printf("pFrame alloc fail!\n"); 97         return -1; 98     } 99     pFrameYUV = av_frame_alloc();100     if (pFrameYUV == NULL)101     {102         printf("pFrameYUV alloc fail!\n");103         return -1;104     }105     //6、得到一帧视频截图的内存大小并分配内存,并将YUV数据填充进去106     numBytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width,107             pCodecCtx->height,1);108     buffer = (uint8_t*) av_mallocz(numBytes * sizeof(uint8_t));109     if (!buffer)110     {111         printf("numBytes :%d , buffer malloc 's mem \n", numBytes);112         return -1;113     }114     //打印信息115     printf("--------------- File Information ----------------\n");116     av_dump_format(pFormatCtx, 0, filename, 0);117     printf("-------------------------------------------------\n");118     av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize,buffer,119             AV_PIX_FMT_YUV420P,pCodecCtx->width, pCodecCtx->height,1);120     //7、得到指定转换格式的上下文**********************************121     img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,122             pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,123             AV_PIX_FMT_YUV420P,124             SWS_BICUBIC,125             NULL, NULL, NULL);126     if (img_convert_ctx == NULL)127     {128         fprintf(stderr, "Cannot initialize the conversion context!\n");129         return -1;130     }131     //***********************************************************132 #if OUTPUT_YUV420P133     fp_yuv = fopen(outfilename, "wb+");134 #endif135     //8、SDL初始化和创建多重windows等准备工作136     if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_VIDEO))137     {138         fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());139         return -1;140     }141     //使用SDL_CreateWindow代替SDL_SetVideoMode142     //创建一个给定高度和宽度、位置和标示的windows。143     screen = SDL_CreateWindow("Simplest ffmpeg player's Window",144     SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, pCodecCtx->width,145             pCodecCtx->height, SDL_WINDOW_OPENGL);146     if (!screen)147     {148         fprintf(stderr, "SDL: could not create window - exiting - %s\n",SDL_GetError());149         return -1;150     }151     //对该window创建一个2D渲染上下文152     sdlRender = SDL_CreateRenderer(screen, -1, 0);153     if (!sdlRender)154     {155         fprintf(stderr, "SDL:cound not create render :    %s\n", SDL_GetError());156         return -1;157     }158     //Create a texture for a rendering context.159     //为一个渲染上下文创建一个纹理160     //IYUV: Y + U + V  (3 planes)161     //YV12: Y + V + U  (3 planes)162     sdlTexture = SDL_CreateTexture(sdlRender, SDL_PIXELFORMAT_IYUV,163             SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);164     if (!sdlTexture)165     {166         fprintf(stderr, "SDL:cound not create Texture :    %s\n", SDL_GetError());167         return -1;168     }169     //建立一个矩形变量,提供后面使用170     sdlRect.x = 0;171     sdlRect.y = 0;172     sdlRect.w = pCodecCtx->width;173     sdlRect.h = pCodecCtx->height;174     //9、正式开始读取数据*****************************************175     while (av_read_frame(pFormatCtx, &packet) >= 0)176     {177         //如果读取的包来自视频流178         if (packet.stream_index == videoStream)179         {180             //从包中得到解码后的帧181             if (avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,&packet) < 0)182             {183                 printf("Decode Error!\n");184                 return -1;185             }186             //如果确定完成得到该视频帧187             if (frameFinished)188             {189                 //转换帧数据格式190                 sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0,191                         pCodecCtx->height,192                         pFrameYUV->data,193                         pFrameYUV->linesize);194 #if OUTPUT_YUV420P195                 y_size = pCodecCtx->width * pCodecCtx->height;196                 fwrite(pFrameYUV->data[0], 1, y_size, fp_yuv);    //Y197                 fwrite(pFrameYUV->data[1], 1, y_size / 4, fp_yuv);  //U198                 fwrite(pFrameYUV->data[2], 1, y_size / 4, fp_yuv);  //V199 #endif200                 //SDL显示~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~201 #if 0202                 SDL_UpdateTexture(sdlTexture,NULL,pFrameYUV->data[0],pFrameYUV->linesize[0]);203 #else204                 SDL_UpdateYUVTexture(sdlTexture, &sdlRect, pFrameYUV->data[0],205                         pFrameYUV->linesize[0], pFrameYUV->data[1],206                         pFrameYUV->linesize[1], pFrameYUV->data[2],207                         pFrameYUV->linesize[2]);208 #endif209                 SDL_RenderClear(sdlRender);210                 SDL_RenderCopy(sdlRender, sdlTexture, NULL, &sdlRect);211                 SDL_RenderPresent(sdlRender);212                 //结束SDL~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~213                 SDL_Delay(40);//延时214             }215         }216         av_free_packet(&packet);//释放读出来的包217     }218     //**************************************************************************************219     //10、释放分配的内存或关闭文件等操作220 #if OUTPUT_YUV420P221     fclose(fp_yuv);222 #endif223     sws_freeContext(img_convert_ctx);224     SDL_Quit();225     av_free(buffer);226     av_free(pFrame);227     av_free(pFrameYUV);228     avcodec_close(pCodecCtx);229     avformat_close_input(&pFormatCtx);230     return EXIT_SUCCESS;231 }232 233 #ifdef _cplusplus234 }235 #endif

把艰辛的劳作看作是生命的必然,

ffmpeg简单视频播放器

相关文章:

你感兴趣的文章:

标签云: