FFmpeg解码封装为类以及Opencv显示播放
2015-08-02 10:58
316 查看
解码函数接口头文件
接口函数实现
main函数测试
//#ifndef __FFMPEG_DECODE_H__ //#define __FFMPEG_DECODE_H__ // Opencv #include <opencv/cv.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> extern "C" { #include "libavutil/avutil.h" #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" //新版本里的图像转换结构需要引入的头文件 #include "libswscale/swscale.h" }; using namespace cv; //#pragma comment(lib, "avcodec.lib") //#pragma comment(lib, "avformat.lib ") //#pragma comment(lib, "avutil.lib ") //#pragma comment(lib, "avdevice.lib ") //#pragma comment(lib, "avfilter.lib ") //#pragma comment(lib, "postproc.lib ") //#pragma comment(lib, "swresample.lib") //#pragma comment(lib, "swscale.lib ") class ffmpegDecode { public: ffmpegDecode(char * file = NULL); ~ffmpegDecode(); cv::Mat getDecodedFrame(); cv::Mat getLastFrame(); int readOneFrame(); int getFrameInterval(); private: ***Frame *pAvFrame; ***FormatContext *pFormatCtx; ***CodecContext *pCodecCtx; ***Codec *pCodec; int i; int videoindex; char *filepath; int ret, got_picture; SwsContext *img_convert_ctx; int y_size; ***Packet *packet; cv::Mat *pCvMat; void init(); void openDecode(); void prepare(); void get(***CodecContext *pCodecCtx, SwsContext *img_convert_ctx,***Frame *pFrame); }; //#endif
接口函数实现
#define __STDC_CONSTANT_MACROS #include "ffmpegDecoder.h" ffmpegDecode :: ~ffmpegDecode() { pCvMat->release(); //释放本次读取的帧内存 av_free_packet(packet); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); } ffmpegDecode :: ffmpegDecode(char * file) { pAvFrame = NULL/**pFrameRGB = NULL*/; pFormatCtx = NULL; pCodecCtx = NULL; pCodec = NULL; pCvMat = new cv::Mat(); i=0; videoindex=0; ret = 0; got_picture = 0; img_convert_ctx = NULL; y_size = 0; packet = NULL; if (NULL == file) { filepath = "opencv.h264"; } else { filepath = file; } init(); openDecode(); prepare(); } void ffmpegDecode :: init() { //ffmpeg注册复用器,编码器等的函数av_register_all()。 //该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等。 //这里注册了所有的文件格式和编解码器的库,所以它们将被自动的使用在被打开的合适格式的文件上。注意你只需要调用 av_register_all()一次,因此我们在主函数main()中来调用它。如果你喜欢,也可以只注册特定的格式和编解码器,但是通常你没有必要这样做。 av_register_all(); //pFormatCtx = avformat_alloc_context(); //打开视频文件,通过参数filepath来获得文件名。这个函数读取文件的头部并且把信息保存到我们给的***FormatContext结构体中。 //最后2个参数用来指定特殊的文件格式,缓冲大小和格式参数,但如果把它们设置为空NULL或者0,libavformat将自动检测这些参数。 if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0) { printf("无法打开文件\n"); return; } //查找文件的流信息,avformat_open_input函数只是检测了文件的头部,接着要检查在文件中的流的信息 if(av_find_stream_info(pFormatCtx)< 0) { printf("Couldn't find stream information.\n"); return; } return; } void ffmpegDecode :: openDecode() { //遍历文件的各个流,找到第一个视频流,并记录该流的编码信息 videoindex = -1; for(i=0; i<pFormatCtx->nb_streams; i++) { if(pFormatCtx->streams[i]->codec->codec_type == ***MEDIA_TYPE_VIDEO) { videoindex = i; break; } } if(videoindex==-1) { printf("Didn't find a video stream.\n"); return; } pCodecCtx = pFormatCtx->streams[videoindex]->codec;//tony,找到解码器 //在库里面查找支持该格式的解码器 pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//定位到具体编码格式视频的解码器 if(pCodec==NULL) { printf("Codec not found.\n"); return; } //打开解码器 if(avcodec_open2(pCodecCtx, pCodec,NULL) < 0) { printf("Could not open codec.\n"); return; } } void ffmpegDecode :: prepare() { //分配一个帧指针,指向解码后的原始帧 pAvFrame = avcodec_alloc_frame(); y_size = pCodecCtx->width * pCodecCtx->height; //分配帧内存 packet = (***Packet *)av_malloc(sizeof(***Packet)); av_new_packet(packet, y_size); //输出一下信息----------------------------- printf("文件信息-----------------------------------------\n"); av_dump_format(pFormatCtx,0,filepath,0); //av_dump_format只是个调试函数,输出文件的音、视频流的基本信息了,帧率、分辨率、音频采样等等 printf("-------------------------------------------------\n"); } int ffmpegDecode :: readOneFrame() { int result = 0; result = av_read_frame(pFormatCtx, packet); return result; } cv::Mat ffmpegDecode :: getDecodedFrame() { if(packet->stream_index == videoindex) { //解码一个帧 ret = avcodec_decode_video2(pCodecCtx, pAvFrame, &got_picture, packet); if(ret < 0) { printf("解码错误\n"); return cv::Mat(); } if(got_picture) { //根据编码信息设置渲染格式 if(img_convert_ctx == NULL) { img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, ***_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL); } //----------------------opencv if (pCvMat->empty()) { pCvMat->create(cv::Size(pCodecCtx->width, pCodecCtx->height),CV_8UC3); } if(img_convert_ctx != NULL) { get(pCodecCtx, img_convert_ctx, pAvFrame); if (pCvMat->data==NULL) { printf("No image data, error at %d lines.", __LINE__); getchar(); } } } } av_free_packet(packet); return *pCvMat; } cv::Mat ffmpegDecode :: getLastFrame() { ret = avcodec_decode_video2(pCodecCtx, pAvFrame, &got_picture, packet); if(got_picture) { //根据编码信息设置渲染格式 img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); if(img_convert_ctx != NULL) { get(pCodecCtx, img_convert_ctx,pAvFrame); } } return *pCvMat; } void ffmpegDecode :: get(***CodecContext * pCodecCtx, SwsContext * img_convert_ctx, ***Frame * pFrame) { if (pCvMat->empty()) { pCvMat->create(cv::Size(pCodecCtx->width, pCodecCtx->height),CV_8UC3); } ***Frame *pFrameRGB = NULL; uint8_t *out_bufferRGB = NULL; pFrameRGB = avcodec_alloc_frame(); //给pFrameRGB帧加上分配的内存; int size = avpicture_get_size(***_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); out_bufferRGB = (uint8_t *)av_malloc(size); avpicture_fill((***Picture *)pFrameRGB, out_bufferRGB, ***_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); //YUV to RGB sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); memcpy(pCvMat->data, out_bufferRGB, size); if (pCvMat->data==NULL) { printf("No image data, error at %d lines.", __LINE__); } av_free(out_bufferRGB); av_free(pFrameRGB); }
main函数测试
int main() { ffmpegDecode ffDecoder("video.flv"); cv::Mat pCvMat; cvNamedWindow("RGB",1); while (ffDecoder.readOneFrame() >= 0) { pCvMat = ffDecoder.getDecodedFrame(); if (pCvMat.data != NULL) { imshow("RGB", pCvMat); waitKey(1); } } cvDestroyWindow("RGB"); return 0; }
相关文章推荐
- linux grep命令
- 为什么margin-top值不是作用域父元素
- Linux文件内容查阅 - cat, tac, nl, more, less, head, tail, od
- Linux文件内容查阅 - cat, tac, nl, more, less, head, tail, od
- wc命令
- shell常用命令
- VS2013 MFC opencv 播放视频
- VS2013 MFC opencv 播放视频
- Syslogger: Forward syslog to Apache Kafka
- linux常用命令一之文件处理命令
- Tomcat的server.xml数据源JDBC配置
- 修改linux root密码
- topcpder SRM 664 div2 A,B,C BearCheats , BearPlays equalPiles , BearSorts (映射)
- linux下echo命令
- 手把手带你自制Linux系统之一 准备工作
- 3D开发--CopperCube
- ABP分层架构
- linux虚拟机下Hadoop集群分布式配置
- 使用Hadoop Streaming
- dlopen 方式调用 Linux 的动态链接库