// FFMpeg + OpenCV demo
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef __cplusplus
}
#endif
#include
static void CopyDate(AVFrame *pFrame, int width, int height, int time);
static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame);
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
int result = 0;
av_register_all(); // 注册所有FFmpeg库所支持的文件格式和codec
AVFormatContext* pFormatCtx;
char* filename = "up.mp4"; //输入文件名
// step1: 打开媒体文件,最后2个参数是用来指定文件格式,buffer大小和格式参数,设置成NULL的话,libavformat库会自动去探测它们
result = avformat_open_input(&pFormatCtx, filename, NULL, NULL);
if (result != 0)
{
cout << "open file fail" << endl;
return -1;
}
cout << "open file succ" << endl;
// step2: 查找信息流的信息
result = avformat_find_stream_info(pFormatCtx, NULL);
if (result != 0)
{
cout << "find stream fail" << endl;
return -1;
}
cout << "find stream succ" << endl;
// step3: 打印信息
//av_dump_format(pFormatCtx, 0, filename, 0);
// step4:找到video流数据
int i = 0;
int videoStream = -1;
AVCodecContext* pCodecCtx = NULL;
for (i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
}
if (videoStream == -1)
{
cout << "find stream video fail" << endl;
return -1;
}
cout << "find stream video succ." << endl;
// 得到video编码格式
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
// step5: 得到解码器
AVCodec* pCodec = NULL;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL)
{
cout << "find decoder fail" << endl;
return -1;
}
cout << "find decoder succ" << endl;
result = avcodec_open2(pCodecCtx, pCodec, NULL);
if (result != 0)
{
cout << "open codec fail" << endl;
return -1;
}
cout << "open codec succ" << endl;
// step6: 申请原始数据帧 和 RGB帧内存
AVFrame* pFrame = NULL;
AVFrame* pFrameRGB = NULL;
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
if (pFrame == NULL || pFrameRGB == NULL)
{
return -1;
}
int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
uint8_t* buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture*)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
int frameFinishsed = 0;
AVPacket packet;
i = 0;
// step7: 创建格式转化文本
SwsContext * pSwxCtx = sws_getContext(
pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24,
SWS_BILINEAR, 0, 0, 0);
cv::Mat image(pCodecCtx->height, pCodecCtx->width, CV_8UC3);
int b = 0;
int g = 1;
int r = 2;
while (true)
{
// 得到数据包
result = av_read_frame(pFormatCtx, &packet);
if (result != 0)
{
break;
}
if (packet.stream_index == videoStream)
{
// 解码
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinishsed, &packet);
if (frameFinishsed)
{
// 转换
sws_scale(pSwxCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
for (int m = 0; m < pCodecCtx->height; m++)
{
for (int n = 0; n < pCodecCtx->width; n++)
{
image.at(m, n)[r] = pFrameRGB->data[0][3 * (m*pCodecCtx->width + n) + 0];
image.at(m, n)[g] = pFrameRGB->data[0][3 * (m*pCodecCtx->width + n) + 1];
image.at(m, n)[b] = pFrameRGB->data[0][3 * (m*pCodecCtx->width + n) + 2];
}
}
cv::imshow("pic", image);
cv::waitKey(30);
}
}
av_free_packet(&packet);
}
avformat_close_input(&pFormatCtx);
system("pause");
return 0;
}