`
xiang37
  • 浏览: 431557 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

采用FFmpeg解帧,并保持到JPG格式文件

 
阅读更多

其实研究这个的目的主要是今后给Java项目使用。好久没看C了,公司业务大部分都是编解码视频的,带着一股冲动研究了一下。懂得了一点皮毛。

 

首先下载ffmpeg的开发包以及依赖包,当然也可以下载源码。

http://ffmpeg.zeranoe.com/builds/

 

其次为了编码为JPEG格式的图片,需要下载Independent JPEG Group

http://www.ijg.org/files/jpegsr9.zip

下载IJG后,需要对源码进行编译,生成静态库,

本人是使用VS2010编译的,其中含有install.txt文件讲述了怎么讲make file文件转换为VS工程文件,使用下面命令可以做到:

NMAKE /f makefile.vc  setup-v10

其中会遇到windows环境变量中没有NMAKE 的问题,还有Win32.Mak找不到的问题。

1、找到nmake.exe配一下环境变量

2、在makefile.vc文件中找到Win32.Mak,将相应路径添加上,如:

!include <C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include\Win32.Mak>

 

 

 

 

#include <math.h>
#include <windows.h>

#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <jpeglib.h>
#include <setjmp.h>

#define inline __inline
#define snprintf _snprintf

#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096


#pragma comment (lib, "Ws2_32.lib")  
#pragma comment (lib, "avcodec.lib")
#pragma comment (lib, "avdevice.lib")
#pragma comment (lib, "avfilter.lib")
#pragma comment (lib, "avformat.lib")
#pragma comment (lib, "avutil.lib")
#pragma comment (lib, "swresample.lib")
#pragma comment (lib, "swscale.lib")
 #pragma comment(lib, "jpeg.lib")

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

static void yuv420p_save(AVFrame *pFrame, int width, int height, int iFrame);

static void bmp_save(AVFrame *pFrame, int width, int height, int iFrame);

static void saveFrame_jpg(uint8_t *pRGBBuffer, int iFrame, int width, int height);

int main(int argc, char **argv)
{
	AVFormatContext *pFormatCtx = NULL;
	char            *fileName = "E:\\aa.rm";
	int             i,videoStream;
	AVCodecContext  *pCodecCtx;
	AVCodec         *pCodec;
	AVFrame         *pFrame;
	AVFrame         *pFrameRGB;
	int             numBytes;
	uint8_t         *buffer;
	AVPacket        packet;
	int             frameFinished;
	struct SwsContext *img_convert_ctx = NULL;

    av_register_all();
	
	if(avformat_open_input(&pFormatCtx, fileName, NULL, NULL)!=0)
	{
		printf("can not open");
		return -1;
	}

	if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
	{
		printf("can not find");
		return -1;
	}

	av_dump_format(pFormatCtx, -1, fileName, 0);

	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 )
	{
		printf("not find videoStream");
		return -1;
	}

	pCodecCtx = pFormatCtx->streams[videoStream]->codec;

	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
	if ( pCodec == NULL )
	{
		return -1;
	}

	if( avcodec_open2(pCodecCtx, pCodec, NULL) < 0 )
	{
		return -1;
	}

	pFrame = av_frame_alloc();
	if( pFrame == NULL )
	{
		return -1;
	}

	pFrameRGB = av_frame_alloc();
	if( pFrameRGB == NULL )
	{
		return -1;
	}

	numBytes = avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);

	buffer = av_malloc(numBytes);

	avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);

	
	img_convert_ctx = sws_getCachedContext(img_convert_ctx, pCodecCtx->width, pCodecCtx->height,
		pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);

	i = 0;
	while( av_read_frame(pFormatCtx, &packet) >= 0 )
	{
		if( packet.stream_index == videoStream )
		{
			avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
			if ( frameFinished )
			{
				
				if (!img_convert_ctx )
				{
					fprintf(stderr, "Cannot initialize sws conversion context\n");
					exit(1);
				}

				sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
					pFrameRGB->data, pFrameRGB->linesize);

				if(i++<5)
				{
					//SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
					//yuv420p_save(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
					//bmp_save(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
					saveFrame_jpg(pFrameRGB->data[0], i, pCodecCtx->width, pCodecCtx->height);
					
				}
			}
		}
		if(i > 5)
		{
			break;
		}
	}
	av_free_packet(&packet);
	
	av_free(buffer);
	av_free(pFrame);
	av_free(pFrameRGB);
	avcodec_close(pCodecCtx);
	avformat_close_input(&pFormatCtx);
	

    return 0;
}

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

	sprintf(szFilename, "frame%d.jpg", iFrame);
	pFile = fopen(szFilename, "wb");
	if( !pFile )
	{
		return;
	}

	fprintf(pFile, "P6\n%d %d\n255\n", width, height);
	for ( y=0; y<height; y++ )
	{
		fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3, pFile);
	}

	fclose(pFile);
}

static void yuv420p_save(AVFrame *pFrame, int width, int height, int iFrame)
{
	int i = 0;
	FILE *pFile;
	char szFilename[32];

	int height_half = height / 2, width_half = width / 2;
	int y_wrap = pFrame->linesize[0];
	int u_wrap = pFrame->linesize[1];
	int v_wrap = pFrame->linesize[2];

	unsigned char *y_buf = pFrame->data[0];
	unsigned char *u_buf = pFrame->data[1];
	unsigned char *v_buf = pFrame->data[2];
	sprintf(szFilename, "frame%d.jpg", iFrame);
	pFile = fopen(szFilename, "wb");

	//save y
	for (i = 0; i < height; i++)
		fwrite(y_buf + i * y_wrap, 1, width, pFile);
	fprintf(stderr, "===>save Y success\n");

	//save u
	for (i = 0; i < height_half; i++)
		fwrite(u_buf + i * u_wrap, 1, width_half, pFile);
	fprintf(stderr, "===>save U success\n");

	//save v
	for (i = 0; i < height_half; i++)
		fwrite(v_buf + i * v_wrap, 1, width_half, pFile);
	fprintf(stderr, "===>save V success\n");

	fflush(pFile);
	fclose(pFile);
}


static void bmp_save(AVFrame *pFrame, int width, int height, int iFrame)
{
	BITMAPFILEHEADER bmpheader;
	BITMAPINFO bmpinfo;
	int y = 0;
	FILE *pFile;
	char szFilename[32];

	unsigned char *y_buf = pFrame->data[0];
	sprintf(szFilename, "frame%d.bmp", iFrame);
	pFile = fopen(szFilename, "wb");

	bmpheader.bfReserved1 = 0;
	bmpheader.bfReserved2 = 0;
	bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bmpheader.bfSize = bmpheader.bfOffBits + width*height*24/8;

	bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmpinfo.bmiHeader.biWidth = width;
	bmpinfo.bmiHeader.biHeight = -height;
	bmpinfo.bmiHeader.biPlanes = 1;
	bmpinfo.bmiHeader.biBitCount = 24;
	bmpinfo.bmiHeader.biCompression = BI_RGB;
	bmpinfo.bmiHeader.biSizeImage = 0;
	bmpinfo.bmiHeader.biXPelsPerMeter = 100;
	bmpinfo.bmiHeader.biYPelsPerMeter = 100;
	bmpinfo.bmiHeader.biClrUsed = 0;
	bmpinfo.bmiHeader.biClrImportant = 0;

	fwrite(&bmpheader, sizeof(BITMAPFILEHEADER), 1, pFile);
	fwrite(&bmpinfo.bmiHeader, sizeof(BITMAPINFOHEADER), 1, pFile);

	fwrite(pFrame->data[0], width*height*24/8, 1, pFile);

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

	//fflush(pFile);
	fclose(pFile);
}

static void saveFrame_jpg(uint8_t *pRGBBuffer, int iFrame, int width, int height)
{

	struct jpeg_compress_struct cinfo;

	struct jpeg_error_mgr jerr;

	char szFilename[1024];
	int row_stride;

	FILE *fp;

	JSAMPROW row_pointer[1];   // 一行位图

	cinfo.err = jpeg_std_error(&jerr);

	jpeg_create_compress(&cinfo);

	
	sprintf(szFilename, "test%d.jpg", iFrame);//图片名字为视频名+号码
	fp = fopen(szFilename, "wb");
	
	if(fp == NULL)
        	return;

	jpeg_stdio_dest(&cinfo, fp);

	cinfo.image_width = width;    // 为图的宽和高,单位为像素 
	cinfo.image_height = height;
	cinfo.input_components = 3;   // 在此为1,表示灰度图, 如果是彩色位图,则为3 
	cinfo.in_color_space = JCS_RGB; //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像

	jpeg_set_defaults(&cinfo); 
	jpeg_set_quality (&cinfo, 80, 1);

	jpeg_start_compress(&cinfo, TRUE);

	
	row_stride = cinfo.image_width * 3;//每一行的字节数,如果不是索引图,此处需要乘以3

	// 对每一行进行压缩
	while (cinfo.next_scanline < cinfo.image_height) {
		row_pointer[0] = &(pRGBBuffer[cinfo.next_scanline * row_stride]);
		jpeg_write_scanlines(&cinfo, row_pointer, 1);
	}

	jpeg_finish_compress(&cinfo);
	jpeg_destroy_compress(&cinfo);

	fclose(fp);
}

 

最后,将相应的lib和dll给链接上,以及头文件给添加好,应该没问题。

后续思考方向为如何添加自己的解码器,比如海康大华的SDK接入,封装dll给Java调用,希望更上一层楼吧。

 

 

 

分享到:
评论

相关推荐

    最新版本ffmpeg提取任意格式视频帧并保存

    下面将详细介绍如何使用FFmpeg来提取视频帧,并保存为图像文件。 首先,你需要从提供的链接或FFmpeg官网下载最新版本的FFmpeg。安装完成后,你可以通过命令行界面来调用它。在Windows系统中,这通常意味着打开命令...

    FFmpeg解码视频保存为一帧帧jpg图片

    本话题主要围绕如何使用FFmpeg解码视频并将其保存为一帧帧的JPEG图片进行讲解。 首先,我们需要理解FFmpeg的基本命令行操作。FFmpeg通过命令行参数来完成各种任务,例如`-i`用于指定输入文件,`-vf`用于设置视频...

    ffmpeg转换MP4为JPG帧图片

    在本场景中,我们将关注如何使用FFmpeg将MP4视频文件转换为一系列JPG格式的图片帧。 首先,我们需要了解FFmpeg的基本命令结构。FFmpeg的命令行工具通常以以下形式运行: ``` ffmpeg [options] -i input_file ...

    ffmpeg将一个视频文件解码输出bmp和jpg文件

    总结,通过FFmpeg,我们可以方便地将视频文件解码为图像,并选择性地输出为BMP或JPG格式。理解FFmpeg的解码过程和参数设置,有助于我们在多媒体处理中进行更高级的操作,如视频转码、截图、画面裁剪等。

    ffmpeg h264 转换jpg

    在本场景中,我们将重点讨论如何利用FFmpeg 3.4.1版本,针对64位系统,并使用VS2012编译环境,将H264编码的视频帧数据转换成JPEG图像。 H264是一种高效的视频编码标准,广泛应用于高清视频录制、传输和播放。它通过...

    ffmpeg封装H264成MP4、AVI视频格式,及提取出png、jpg格式图片

    FFmpeg可以方便地从视频流中提取指定帧作为PNG或JPG格式的图片。PNG是一种无损压缩的图像格式,适合保存需要保留原始像素信息的图像;而JPG则采用有损压缩,适合于照片和色彩丰富的图像,因为人眼对一定级别的图像...

    ffmpeg视频生成jpg图片_1

    在本示例"ffmpeg视频生成jpg图片_1"中,我们将探讨如何利用FFmpeg从视频文件中提取静态图像并保存为JPEG(jpg)格式的图片。 首先,FFmpeg的基本命令结构是`ffmpeg -i 输入文件 -vf "滤镜表达式" -o 输出文件`。在...

    ffmpeg库实现jpeg图像转yuv格式数据源码

    在`__main.cpp`文件中,我们首先需要包含必要的FFmpeg头文件,并初始化FFmpeg全局变量。这通常包括`#include &lt;libavcodec/avcodec.h&gt;`,`#include &lt;libavformat/avformat.h&gt;`,`#include &lt;libswscale/swscale.h&gt;`等...

    ffmpeg转换MP4为JPG帧图片源代码方案资料

    本资料主要关注的是如何使用FFmpeg将MP4视频转换为JPG帧图片,这对于视频预览、视频截图或者进行图像分析等场景非常有用。以下是关于这个主题的详细知识讲解: 1. FFmpeg基础: FFmpeg是一套跨平台的命令行工具,...

    ffmpeg视频解码成YUV,JPG

    综上所述,FFmpeg提供了一套完整的解决方案,用于从视频解码到YUV,再到JPEG的处理,并允许对生成的JPEG文件进行各种定制化操作。通过灵活运用FFmpeg的命令行参数和滤镜,我们可以高效地处理多媒体数据,满足各种...

    ffmpeg库实现bmp转换为jpeg格式图像

    在`rgb2bmp.cpp`文件中,可能会有处理RGB图像到BMP转换的代码,因为BMP格式通常需要将像素数据从RGB转换为特定的内部格式。这个过程与上面的转换略有不同,主要是编码步骤,但基本的图像处理流程是相似的。 `__main...

    ffmpeg 工具,使用ffmpeg 截取Jpg GIF 图片

    FFmpeg可以从视频中提取任意时间点的帧,并将其保存为图像文件。例如,假设我们有一个名为"input.mp4"的视频文件,我们想要在第5秒处截取一帧,可以使用以下命令: ```bash ffmpeg -i input.mp4 -ss 00:00:05 -...

    ffmpeg将png/jpg图片序列转成mp4/avi

    本篇文章将详细介绍如何使用`ffmpeg`和C++编程语言将一系列的PNG或JPG图片序列合成为MP4或AVI格式的视频。 首先,我们需要了解`ffmpeg`的基本原理。`ffmpeg`是一个跨平台的命令行工具,可以用于转换、合并、分割、...

    ffmpeg截帧工具

    4. **输出格式**:默认情况下,FFmpeg会将截取的帧保存为PNG格式,但可以通过修改输出文件名的扩展名来改变格式,如`.jpg`、`.bmp`等。 5. **连续截取**:若需要连续截取多帧,可以使用`ffmpeg`的`-vf`参数配合`...

    java后台利用ffmpeg实现将视频截取某一帧图片并保存

    5. **保存图像**:一旦解码得到视频帧(通常是`org.bytedeco.ffmpeg.avutil.AVFrame`类型),你可以使用`sws_scale()`函数将其转换为RGB格式,以便于保存为常见的图像格式,如JPEG或PNG。`org.bytedeco.ffmpeg....

    利用FFmpeg将Jpeg图片转为任意视频容器格式

    下面,我们详细讲解这个过程,并涉及到的相关知识点。 1. **JPEG图片格式**: JPEG是一种广泛使用的有损图像压缩格式,它通过压缩算法减少文件大小,以适应网络传输和存储需求。这种格式适用于照片和其他色彩丰富...

    ffmpeg视频格式转换

    - 例如,提取视频的第一帧为 JPG 图片:`ffmpeg -i video.mp4 -vf "select='eq(n,0)'" -vframes 1 output.jpg`。 4. **添加水印**: - 添加文本水印:`ffmpeg -i 输入文件 -vf "drawtext=fontfile=/path/to/font....

    javaCV+openCV+FFmpeg实现视频帧转为图像并进行人脸识别(一)

    在本项目中,我们将探讨如何使用JavaCV、OpenCV和FFmpeg库来实现在Java环境中将视频帧转换为图像,并进一步进行人脸识别。首先,我们来理解这三个关键组件: 1. **JavaCV**: JavaCV(Java Computer Vision)是Java...

    ffmpeg视频生成jpg图片_1.rar_ffmpeg_ffmpeg 截图_ffmpeg 视频_ffmpeg生成图片

    在本案例中,我们关注的是FFmpeg如何从视频中生成静态图片,尤其是jpg格式的图像。 首先,我们要理解FFmpeg的基本命令结构。在命令行中,FFmpeg的命令通常由`ffmpeg`开头,后接一系列的选项和参数。例如,要从一个...

    ffmpeg构造声音和图像输出到Mp4

    在本文中,我们将深入探讨如何使用FFmpeg构造声音和图像数据,并将其输出到MP4文件中,同时关注图像的YUV420格式和AAC声音的同步处理。 首先,我们要了解YUV420色彩空间。这是一种广泛应用于数字视频的存储格式,它...

Global site tag (gtag.js) - Google Analytics