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

[续]Java调用DLL视频解帧,并保存第一关键帧到JPG格式文件

阅读更多

本篇文章的前一篇是采用FFmpeg解帧,并保持到JPG格式文件,其中使用了main函数对视频进行了解帧,本篇将针对Java如何调用来实现解帧并输出到文件。

 

一、使用VS2010将其改为Dll输出时,需要改变以下项目属性设置:

1、常规设置

 

2、库目录设置


 

3、预编译头设置



 

4、预处理设置


 

_INTEL
WIN32
_DEBUG
_CONSOLE
_Windows
_CRT_SECURE_NO_DEPRECATE

 
  二、基于上篇文章代码我们添加如下函数声明以及实现

 

 

 

_declspec(dllexport) int findFKeyFrame(char *videoFilePath, char *frameFile);

int findFKeyFrame(char *videoFilePath, char *frameFile)
{
	AVFormatContext *pFormatCtx = NULL;
	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, videoFilePath, 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, videoFilePath, 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_RGB24, 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 && pFrame->key_frame)
			{
				
				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++<1)
				{
					saveFrameJpg(pFrameRGB->data[0],frameFile, 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 1;
}

 

 

编译项目,生成DLL,并拷贝其到Java调用类目录下。

 

三、编写Java代码调用DLL

       Java调用dll,肯定会用到JNI,但是此处使用比较常用地JNA框架来调用。JNA相关链接

       可从test包可以查看怎么使用指针类Pointer等等

      

       JNA代码实现如下:

package com.xiva.test.pic;

import java.io.UnsupportedEncodingException;

import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;

/**
 * 
 * <调用DLL读取视频的第一关键帧,并以JPG格式输出到文件>
 * @author xiva
 * @version [1.0, 2014-5-15]
 * @see [相关类/方法]
 * @since [产品、模块版本]
 */
public class ReadVideoKeyFrame
{
 
    public interface VideoDecoder extends Library {
        /**
         * 当前路径是在项目下,而不是bin输出目录下。
         */
        VideoDecoder INSTANCE = (VideoDecoder) Native.loadLibrary("VideoDecoder", VideoDecoder.class);

        public NativeLong findFKeyFrame(Pointer videoFilePath, Pointer frameFile);

    }
    
    public static void main(String[] args) throws UnsupportedEncodingException
    {
        final String ENCODING = "utf8";
        String fileName = "E:\\frame01.jpg";
        String path = "E:\\zookeeper.avi";
        
        Pointer videoFilePath =  new Memory(path.getBytes(ENCODING).length+1);
        Pointer frameFile =  new Memory(fileName.getBytes(ENCODING).length+1);
        
        videoFilePath.setString(0, path);
        frameFile.setString(0, fileName);
        
        NativeLong ret = VideoDecoder.INSTANCE.findFKeyFrame(videoFilePath, frameFile);
        System.out.println(ret);
    }
    
}

 

运行程序,可以看到解帧成功。



 

同样此处还是未解决如何集成其他地解码器,毕竟ffmpeg地解码能力有限;需要后续再次扩展。

 

 

  • 大小: 175.5 KB
  • 大小: 119 KB
  • 大小: 51.9 KB
  • 大小: 104 KB
  • 大小: 22.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics