ffmpeg简单视频播放器
2018-06-18 04:09:17来源:未知 阅读 ()
参考学习雷霄骅的最简单的基于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_YUV420P 133 fp_yuv = fopen(outfilename, "wb+"); 134 #endif 135 //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_SetVideoMode 142 //创建一个给定高度和宽度、位置和标示的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_YUV420P 195 y_size = pCodecCtx->width * pCodecCtx->height; 196 fwrite(pFrameYUV->data[0], 1, y_size, fp_yuv); //Y 197 fwrite(pFrameYUV->data[1], 1, y_size / 4, fp_yuv); //U 198 fwrite(pFrameYUV->data[2], 1, y_size / 4, fp_yuv); //V 199 #endif 200 //SDL显示~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 201 #if 0 202 SDL_UpdateTexture(sdlTexture,NULL,pFrameYUV->data[0],pFrameYUV->linesize[0]); 203 #else 204 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 #endif 209 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_YUV420P 221 fclose(fp_yuv); 222 #endif 223 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 _cplusplus 234 } 235 #endif
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:用C++实现的八皇后问题
下一篇:【c基础】之 文件及其操作
- 1.ffmpeg、ffplay、ffprobe命令使用 2020-05-11
- 关于使用ffmpeg的一些牢骚 2020-05-08
- 加边的无向图--并查集 2020-04-10
- 排兵布阵 2020-02-21
- 二叉树(四)二叉堆 2020-02-03
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash