最简单的基于ffmpeg+SDL的视频播放器
来源:互联网 发布:正版办公软件要买吗 编辑:程序博客网 时间:2024/04/27 10:25
环境:
ubuntu 12.04
Qt 5.5.0
ffmpeg 3.0.1
SDL 2.1
流程图
该播放器解码的流程用图的方式可以表示称如下形式:
SDL显示YUV图像的流程图:
simplest_ffmpeg_player(标准版)代码:
/** * 最简单的基于FFmpeg的视频播放器 * Simplest FFmpeg Player * * 雷霄骅 Lei Xiaohua * leixiaohua1020@126.com * 中国传媒大学/数字电视技术 * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 * * 本程序实现了视频文件的解码和显示(支持HEVC,H.264,MPEG2等)。 * 是最简单的FFmpeg视频解码方面的教程。 * 通过学习本例子可以了解FFmpeg的解码流程。 * This software is a simplest video player based on FFmpeg. * Suitable for beginner of FFmpeg. */#include <stdio.h>#define __STDC_CONSTANT_MACROS#ifdef _WIN32//Windowsextern "C"{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libswscale/swscale.h"#include "SDL/SDL.h"};#else//Linux...#ifdef __cplusplusextern "C"{#endif#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libswscale/swscale.h>#include <SDL/SDL.h>#ifdef __cplusplus};#endif#endif//Full Screen#define SHOW_FULLSCREEN 0//Output YUV420P#define OUTPUT_YUV420P 0int main(int argc, char* argv[]){ //FFmpeg AVFormatContext *pFormatCtx; int i, videoindex; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVFrame *pFrame,*pFrameYUV; AVPacket *packet; struct SwsContext *img_convert_ctx; //SDL int screen_w,screen_h; SDL_Surface *screen; SDL_VideoInfo *vi; SDL_Overlay *bmp; SDL_Rect rect; FILE *fp_yuv; int ret, got_picture; char filepath[]="test.mkv"; 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"); 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; } pCodecCtx=pFormatCtx->streams[videoindex]->codec; pCodec=avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec==NULL){ printf("Codec not found.\n"); return -1; } if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){ printf("Could not open codec.\n"); return -1; } pFrame=av_frame_alloc(); pFrameYUV=av_frame_alloc(); //uint8_t *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); //SDL---------------------------- if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { printf( "Could not initialize SDL - %s\n", SDL_GetError()); return -1; }#if SHOW_FULLSCREEN vi = SDL_GetVideoInfo(); screen_w = vi->current_w; screen_h = vi->current_h; screen = SDL_SetVideoMode(screen_w, screen_h, 0,SDL_FULLSCREEN);#else screen_w = pCodecCtx->width; screen_h = pCodecCtx->height; screen = SDL_SetVideoMode(screen_w, screen_h, 0,0);#endif if(!screen) { printf("SDL: could not set video mode - exiting:%s\n",SDL_GetError()); return -1; } bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY, screen); rect.x = 0; rect.y = 0; rect.w = screen_w; rect.h = screen_h; //SDL End------------------------ packet=(AVPacket *)av_malloc(sizeof(AVPacket)); //Output Information----------------------------- printf("------------- File Information ------------------\n"); av_dump_format(pFormatCtx,0,filepath,0); printf("-------------------------------------------------\n");#if OUTPUT_YUV420P fp_yuv=fopen("output.yuv","wb+");#endif SDL_WM_SetCaption("Simplest FFmpeg Player",NULL); 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); //------------------------------ while(av_read_frame(pFormatCtx, packet)>=0){ if(packet->stream_index==videoindex){ //Decode ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); if(ret < 0){ printf("Decode Error.\n"); return -1; } if(got_picture){ SDL_LockYUVOverlay(bmp); pFrameYUV->data[0]=bmp->pixels[0]; pFrameYUV->data[1]=bmp->pixels[2]; pFrameYUV->data[2]=bmp->pixels[1]; pFrameYUV->linesize[0]=bmp->pitches[0]; pFrameYUV->linesize[1]=bmp->pitches[2]; pFrameYUV->linesize[2]=bmp->pitches[1]; sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);#if OUTPUT_YUV420P int y_size=pCodecCtx->width*pCodecCtx->height; fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V#endif SDL_UnlockYUVOverlay(bmp); SDL_DisplayYUVOverlay(bmp, &rect); //Delay 40ms SDL_Delay(40); } } av_free_packet(packet); } //FIX: Flush Frames remained in Codec while (1) { ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); if (ret < 0) break; if (!got_picture) break; sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); SDL_LockYUVOverlay(bmp); pFrameYUV->data[0]=bmp->pixels[0]; pFrameYUV->data[1]=bmp->pixels[2]; pFrameYUV->data[2]=bmp->pixels[1]; pFrameYUV->linesize[0]=bmp->pitches[0]; pFrameYUV->linesize[1]=bmp->pitches[2]; pFrameYUV->linesize[2]=bmp->pitches[1];#if OUTPUT_YUV420P int y_size=pCodecCtx->width*pCodecCtx->height; fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V#endif SDL_UnlockYUVOverlay(bmp); SDL_DisplayYUVOverlay(bmp, &rect); //Delay 40ms SDL_Delay(40); } sws_freeContext(img_convert_ctx);#if OUTPUT_YUV420P fclose(fp_yuv);#endif SDL_Quit(); //av_free(out_buffer); av_free(pFrameYUV); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 0;}
.pro文件如下:
TEMPLATE = appCONFIG += consoleCONFIG -= app_bundleCONFIG -= qtSOURCES += main.cppinclude(deployment.pri)qtcAddDeployment()LIBS += -lSDL \ -lavcodec \ -lavdevice \ -lavfilter \ -lavformat \ -lswresample \ -lavutil \ -lswscale
编译运行即可。
运行结果
运行结果如下:
ps:本文转载自雷霄骅大神的博客(http://blog.csdn.net/leixiaohua1020)的博文,由于使用的平台不同和ffmpeg版本不同,故稍加修改。
本文出处:
http://blog.csdn.net/leixiaohua1020/article/details/8652605
0 0
- 最简单的基于ffmpeg+SDL的视频播放器
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
- XCode版【100行代码实现最简单的基于FFMPEG+SDL的视频播放器】
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
- 最简单的基于FFMPEG+SDL的视频播放器 v
- 最简单的基于FFMPEG+SDL的视频播放器 v
- Ruby元编程-学习笔记(一)-对象模型
- 解决MyEclipse10.7吃内存以及卡死的方法
- C++开源日志库Glog的使用(VS2010)
- flask数据库可视化SQLite
- CAGradientLayer基本内容详解(实现开机渐变效果)
- 最简单的基于ffmpeg+SDL的视频播放器
- 一、SpringMVC基础入门,创建一个HelloWorld程序
- 二分查找
- 我的C++第四次作业
- commons-digester
- 转载---TCP/IP序列号和确认号详解
- 53. Maximum Subarray
- HDU 1541 Stars
- 在ROS下写Hello ROS!