1. 程式人生 > >FFMpeg視訊解碼+OpenCV顯示

FFMpeg視訊解碼+OpenCV顯示

         雖然OpenCV底層的視訊解碼也是用的FFMpeg,但是自帶的FFMpeg版本過低,其實OpenCV本來就是一個計算機視覺的庫,不是用來進行視訊開發的,所以最好是單獨用FFMpeg進行視訊編解碼,對FFMpeg解碼得到的幀影象利用OpenCV進行處理。參考了網上的一些資料,總結了一下FFMpeg與OpenCV聯合使用的流程,這裡僅僅使用OpenCV的顯示函式,作一個拋磚引玉吧。

    首先,當然是FFMpeg的一些配置,這裡下載最新的FFMpeg SDK(FFMpeg SDK由兩部分組成:1.include(FFMpeg開發所需標頭檔案),lib(靜態庫)  2.dll動態庫),只需要在http://ffmpeg.zeranoe.com/builds/下載即可,include與lib檔案對應於Dev packages,

dll檔案對應於Shared packages。接下來就是一下配置的東西了,我的開發環境是vs2010,至於怎麼配置我就不說了。

         其次,OpenCV的一些配置,這裡我也不說了,都是一些include,lib檔案以及dll檔案通常配置方法。

    最後,做一個簡單的例項,驗證配置正確與否,也瞭解一下FFMpeg與OpenCV聯合使用的大致流程:

// FFMpeg + OpenCV demo
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#ifdef __cplusplus
extern "C" {
#endif

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
}
#endif

#pragma comment(lib, "opencv_core245d.lib")
#pragma comment(lib, "opencv_highgui245d.lib")

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")	
#pragma comment(lib ,"swscale.lib")

static void CopyDate(AVFrame *pFrame,int width,int height,int time);
static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame);

int main (int argc, const char * argv[])
{
	AVFormatContext *pFormatCtx = NULL;
	int             i, videoStream;
	AVCodecContext  *pCodecCtx;
	AVCodec         *pCodec;
	AVFrame         *pFrame; 
	AVFrame         *pFrameRGB;
	AVPacket        packet;
	int             frameFinished;
	int             numBytes;
	uint8_t         *buffer;

	// Register all formats and codecs
	av_register_all();

	// Open video file
	if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
	// if(avformat_open_input(NULL, argv[1], NULL, NULL)!=0)
		return -1; // Couldn't open file

	// Retrieve stream information
	if(av_find_stream_info(pFormatCtx)<0)
		return -1; // Couldn't find stream information

	// Dump information about file onto standard error
	av_dump_format(pFormatCtx, 0, argv[1], false);

	// Find the first video stream
	videoStream=-1;
	for(i=0; i<pFormatCtx->nb_streams; i++)
		if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
		{
			videoStream=i;
			break;
		}
		if(videoStream==-1)
			return -1; // Didn't find a video stream

		// Get a pointer to the codec context for the video stream
		pCodecCtx=pFormatCtx->streams[videoStream]->codec;

		// Find the decoder for the video stream
		pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
		if(pCodec==NULL)
			return -1; // Codec not found

		// Open codec
		if(avcodec_open2(pCodecCtx, pCodec, 0)<0)
			return -1; // Could not open codec

		// Hack to correct wrong frame rates that seem to be generated by some codecs
		if(pCodecCtx->time_base.num>1000 && pCodecCtx->time_base.den==1)
			pCodecCtx->time_base.den=1000;

		// Allocate video frame
		pFrame=avcodec_alloc_frame();

		// Allocate an AVFrame structure
		pFrameRGB=avcodec_alloc_frame();
		if(pFrameRGB==NULL)
			return -1;

		// Determine required buffer size and allocate buffer
		numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
			pCodecCtx->height);

		//buffer=malloc(numBytes);
		buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

		// Assign appropriate parts of buffer to image planes in pFrameRGB
		avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
			pCodecCtx->width, pCodecCtx->height);

		// Read frames and save first five frames to disk
		i=0;
		long prepts = 0;
		while(av_read_frame(pFormatCtx, &packet)>=0)
		{
			// Is this a packet from the video stream?
			if(packet.stream_index==videoStream)
			{
				// Decode video frame
				avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

				// Did we get a video frame?
				if(frameFinished)
				{
					static struct SwsContext *img_convert_ctx;

#if 0
					// Older removed code
					// Convert the image from its native format to RGB swscale
					img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, 
						(AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, 
						pCodecCtx->height);

					// function template, for reference
					int sws_scale(struct SwsContext *context, uint8_t* src[], int srcStride[], int srcSliceY,
						int srcSliceH, uint8_t* dst[], int dstStride[]);
#endif
					// Convert the image into YUV format that SDL uses
					if(img_convert_ctx == NULL) {
						int w = pCodecCtx->width;
						int h = pCodecCtx->height;

						img_convert_ctx = sws_getContext(w, h, 
							pCodecCtx->pix_fmt, 
							w, h, PIX_FMT_RGB24, SWS_BICUBIC,
							NULL, NULL, NULL);
						if(img_convert_ctx == NULL) {
							fprintf(stderr, "Cannot initialize the conversion context!\n");
							exit(1);
						}
					}
					int ret = sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, 
						pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
#if 0 
					// this use to be true, as of 1/2009, but apparently it is no longer true in 3/2009
					if(ret) {
						fprintf(stderr, "SWS_Scale failed [%d]!\n", ret);
						exit(-1);
					}
#endif
					// Save the frame to disk
					if(i++ <= 5)
						SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);

					CopyDate(pFrameRGB, pCodecCtx->width, pCodecCtx->height,packet.pts-prepts);
					prepts = packet.pts;
				}
			}

			// Free the packet that was allocated by av_read_frame
			av_free_packet(&packet);
		}

		// Free the RGB image
		//free(buffer);
		av_free(buffer);
		av_free(pFrameRGB);

		// Free the YUV frame
		av_free(pFrame);

		// Close the codec
		avcodec_close(pCodecCtx);

		// Close the video file
		av_close_input_file(pFormatCtx);

		system("Pause");

		return 0;
}

static void CopyDate(AVFrame *pFrame,int width,int height,int time) 
{
	if(time <=0 ) time = 1;

	int		nChannels;
	int		stepWidth;
	uchar*	pData;	
	cv::Mat frameImage(cv::Size(width, height), CV_8UC3, cv::Scalar(0));
	stepWidth = frameImage.step;
	nChannels = frameImage.channels();
	pData	  = frameImage.data;
	
	for(int i = 0; i < height; i++)
	{
		for(int j = 0; j < width; j++)
		{
			pData[i*stepWidth+j*nChannels+0] = pFrame->data[0][i*pFrame->linesize[0]+j*nChannels+2];
			pData[i*stepWidth+j*nChannels+1] = pFrame->data[0][i*pFrame->linesize[0]+j*nChannels+1];
			pData[i*stepWidth+j*nChannels+2] = pFrame->data[0][i*pFrame->linesize[0]+j*nChannels+0];
		}
	}

	cv::namedWindow("Video", cv::WINDOW_NORMAL);
	cv::imshow("Video", frameImage);
	cv::waitKey(time);
}

static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
	FILE *pFile;
	char szFilename[32];
	int  y;

	// Open file
	sprintf(szFilename, "frame%d.ppm", iFrame);
	pFile=fopen(szFilename, "wb");
	if(pFile==NULL)
		return;

	// Write header
	fprintf(pFile, "P6\n%d %d\n255\n", width, height);

	// Write pixel data
	for(y=0; y<height; y++)
		fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

	// Close file
	fclose(pFile);
}

結果:

相關推薦

FFMpeg視訊解碼+OpenCV顯示

         雖然OpenCV底層的視訊解碼也是用的FFMpeg,但是自帶的FFMpeg版本過低,其實OpenCV本來就是一個計算機視覺的庫,不是用來進行視訊開發的,所以最好是單獨用FFMpeg進行視訊編解碼,對FFMpeg解碼得到的幀影象利用OpenCV進行處理。參考

android全平臺編譯ffmpeg視訊解碼器實踐

目錄 配置環境 新建decode工程 配置環境 作業系統: ubuntu 16.05 注意: ffmpeg庫的編譯使用的是android-ndk-r10e版本,使用高版本編譯會報錯 而android-studio工程中配合cmake使用的版本則是a

android 基於FFmpeg視訊解碼

FFmpeg一個集錄制、轉換、音/視訊編碼解碼功能,強大的音訊處理方案,如何在Android平臺上執行? 1 ,接下來我們需要使用ndk去編譯獲取ffmpeg工具庫,生成.so名稱規範化,有了這些庫才可以利用jni使用在我們Android平臺

ffmpeg解碼h264檔案,opencv顯示

H264.h #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> #include <winsock2

FFmpeg(8)-開啟和配置音視訊解碼器(avcodec_find_decoder()、avcodec_alloc_context3())

一.avcodec_find_decoder 獲取解碼器。在使用之前必須保證所用到的解碼器已經註冊,最簡單的就是呼叫avcodec_register_all() 函式,就像之前註冊解封裝器的時候,也要註冊一下。。 AVCodec *avcodec_find_decoder(enum AVCodecID i

視訊解碼的理論和實踐2:Ffmpeg視訊解碼

近幾年,視訊編解碼技術在理論及應用方面都取得了重大的進展,越來越多的人想要了解編解碼技術。因此,網易雲信研發工程師為大家進行了歸納梳理,從理論及實踐兩個方面簡單介紹視訊編解碼技術。   相關閱讀推薦 《視訊直播關鍵技術:流暢、擁塞和延時追趕》 《視訊直播技術詳解:直播的推流

FFMPEG視訊解碼流程&MP4音視訊檔案流讀取(轉)

1.播放多媒體檔案步驟 通常情況下,我們下載的視訊檔案如MP4,MKV、FLV等都屬於封裝格式,就是把音視訊資料按照相應的規範,打包成一個文字檔案。我們可以使用MediaInfo這個工具檢視媒體檔案的相關資訊。 所以當我們播放一個媒體檔案時,通常需要經過以下幾個步驟

ffmpeg的那點小事兒--ffmpeg的匯入和視訊解碼,YUV儲存(ffmpeg4.0.2)

一、ffmpeg開發的基本知識瞭解        第一點:一個視訊播放流程              通常看到視訊格式:mp4、mov、flv、wmv等等…              稱之為:封裝格式                   第二點:視訊播放器 兩種模

OpenCV開發】OpenCV:使用VideoCapture類進行視訊讀取和顯示

註釋比較詳盡,相信大家都能看得懂,這裡再做幾點補充: 1.由於原視訊是網路攝像頭採集的,所以有很多雪花點,在這裡進行了簡單的均值濾波處理。 2.雖然VideoCapture類中有grab(捕獲下一幀)和retrieve(對該幀進行解碼)操作,但是直接用read比較簡單。 3.get函式的功能很強大,

ffmpeg系列之兩種視訊解碼方式

方式一: #include "myplayer.h" #include <QtWidgets/QApplication> #pragma comment(lib,"avformat.lib") #pragma comment(lib,"avutil.lib")

一個純粹的視訊解碼程式(基於FFMPEG 4.0,在Ubuntu 14.04下驗證)

程式功能:將指定的視訊檔案,解碼為原始YUV資料,只包含視訊流。開發環境:Ubuntu 14.04, GCC 4.8.4, FFMPEG 4.0編譯方法: 將程式碼copy命名為SimpleDecoder.c,與Makefile放置於同一目錄下,執行 make 即可。執行方法

Live555+FFMPEG+ddraw實現H264碼流接收,解碼顯示

1)H264碼流接收採用的是live555,live555會將sps,pps,I幀,p幀都是單獨的包過來的,在接收到Buffer,需要對它進行組成幀,live555自己支援I幀和P幀的組幀的,但是我們交給ffmpeg前,必須對在每幀之前插入00 00 00 01開始碼,同時

opencv顯示一張影象和播放一段視訊,寫入視訊到檔案

#include "mainwindow.h" #include <QApplication> #include <iostream> #include <string> #include <sstream> us

海康網路攝像機視訊資料的獲取及使用opencv顯示

最近要使用海康威視攝像機獲取資料做處理。主要是藉助Opencv這個工具,所以做了一下步驟。 我用的是基於Qt+opencv的來顯示海康資料的。本人海康的型號為:DS-2CD2820FD 1、海康sdk開發環境的配置(我只給出我的配置路徑,視具體情況而定)

FFmpeg視訊解碼同步播放流程

資料接收後處理流程及階段示意圖:1、接收導資料(Trans Stage)2、新建音、視訊解碼執行緒(Parse Stage)3、將解碼好的資料分別放入佇列(Store Stage)4、使用有序的資料結構

ffmpeg實現H.264視訊解碼-1

▶ ffmpeg是一個優秀的開源多媒體編解碼集合 ▶ ffmpeg的libavcodec完成音視訊的編碼或解碼 ▶ H.264視訊解碼主要由H264.c實現 ▶ H264.c能夠流暢解碼x264編碼工程的碼流 ▶ ffmpeg的H.264解碼過程包括初始

javaCV開發詳解之2:推流器實現,推本地攝像頭視訊到流媒體伺服器以及攝像頭錄製視訊功能實現(基於javaCV-FFMPEG、javaCV-openCV)

javaCV系列文章: 補充篇: 歡迎大家積極開心的加入討論群 javacpp-ffmpeg: 前言: 本章將在上一章的基礎上,增加視訊推流到流媒體伺服器和視訊錄製的功能; 功能:實現邊播放邊錄製/推流,停止預覽即停止錄製/推流 提示:

opencv 顯示一個圖片/播放視訊

//顯示圖片 #include"highgui.h" int main(int argc,char **argv) {     IplImage *img=NULL;     char *imgname="E:/實驗/image/1.jpg";     img=cvLoad

RTSP取流+FFmpeg解碼+OpenGL顯示

該DEMO集合RTSP取流、FFmpeg解碼、OpenGL視訊顯示,自己記錄一下,也跟大家分享一下。 該DEMO參考了以下網站: 1、https://github.com/htwahzs/Rts

centos7下視訊解碼播放環境搭建(ffmpeg等庫編譯)

1.軟體環境 作業系統環境:centos7 ffmpeg原始碼: github上的master版本(當前官網的3.4.1版本有bug,在主幹中修復了'x264_bit_depth' undeclared) 2.編譯與安裝 設定環境變數:(可以在/root/.bash