1. 程式人生 > >java呼叫FFmpeg解碼本地檔案 使用Javacv

java呼叫FFmpeg解碼本地檔案 使用Javacv

package com.aast.test;
import java.io.*;
import java.nio.ByteBuffer;

import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.Cast;

//ffmpeg
import static org.bytedeco.javacpp.avcodec.*;
import static org.bytedeco.javacpp.avformat.*;
import static org.bytedeco.javacpp.avutil.*;
import static org.bytedeco.javacpp.swscale.*;
import static org.bytedeco.javacpp.avformat.AVFormatContext.*;

//opencv
import static  org.bytedeco.javacpp.opencv_core.* ;
import static  org.bytedeco.javacpp.opencv_imgcodecs.* ;
import static  org.bytedeco.javacpp.opencv_stitching.* ;
import static  org.bytedeco.javacpp.opencv_highgui.* ;

public class FFmpegRead {
	static InputStream in=null;
	final int BUF_SIZE = 1400;

	Read_packet_Pointer_BytePointer_int read_buffer=new Read_packet_Pointer_BytePointer_int(){

		@Override
		public int call(Pointer opaque, BytePointer buf, int buf_size) {
			byte[] bytebuf=new byte[buf_size];
			int size=-1;
			try {
				size = in.read(bytebuf, 0, buf_size);
			} catch (IOException e) {
				e.printStackTrace();
			}
			// arg1=new BytePointer(ByteBuffer.wrap(buf));
			buf.position(0);
			buf.put(bytebuf, 0, size);
			return size;
		}
	};
	public FFmpegRead() throws FileNotFoundException {
		AVFrame  pFrame = null;
		AVFrame  pFrameRGB = null;
		AVIOContext  pIoCtx=null;
		AVInputFormat  pInputFmt = new AVInputFormat();
		AVFormatContext  pFormatCtx = null;
		AVCodecContext  pCodecCtx = null;
		AVCodec  pCodec = null;
		AVPacket  packet =null;
		SwsContext   pSwxCtx  =null;
		in = new FileInputStream("E:/test.h264");
		
		av_register_all(); //註冊所有FFmpeg庫所支援的檔案格式和codec
		avformat_network_init();
		int result = 0;
		// Pointer inputBuffer = av_malloc(BUF_SIZE);
		// BytePointer inputBuffer=(BytePointer) av_malloc(BUF_SIZE);
		byte[] buf=new byte[BUF_SIZE];
//		BytePointer inputBuffer=new BytePointer(ByteBuffer.wrap(buf));
		 BytePointer inputBuffer = new BytePointer(av_malloc(BUF_SIZE));
		pIoCtx = avio_alloc_context(inputBuffer, BUF_SIZE, 0, null, read_buffer, null,null);

		int ret = av_probe_input_buffer2(pIoCtx, pInputFmt, (BytePointer)null, (Pointer)null, 0, 0);
//		int ret = av_probe_input_buffer2(pIoCtx, pInputFmt, "0", null, 0, 0);
		if (ret < 0) {
			System.out.println("探測失敗");
			return ;
		}
		System.out.println("視訊格式:"+pInputFmt.name()+"  "+pInputFmt.long_name());
		pFormatCtx = avformat_alloc_context();
		pFormatCtx.pb(pIoCtx);
		// step1: 開啟媒體檔案,最後2個引數是用來指定檔案格式,buffer大小和格式引數,設定成null的話,libavformat庫會自動去探測它們
		result = avformat_open_input(pFormatCtx, "0", null, null);
		//result = avformat_open_input(pFormatCtx, "0",pInputFmt, nullptr); //avformat_close_input
		if (result != 0)
		{
			System.out.println("open file fail");
			return  ;
		}
		// step2:查詢資訊流的資訊
		result = avformat_find_stream_info(pFormatCtx, (PointerPointer<Pointer>)null);
		if (result != 0)
		{
			System.out.println("find stream fail");
			return  ;
		}
		// step3: 列印資訊
		// av_dump_format(pFormatCtx, 0, filename, 0);


		// step4:找到video流資料
		int i = 0;
		int videoStream = -1;


		for (i = 0; i < pFormatCtx.nb_streams(); i++){
			if (pFormatCtx.streams(i).codecpar().codec_type() == AVMEDIA_TYPE_VIDEO){
				videoStream = i;
				break;
			}
		}


		if (videoStream == -1){
			System.out.println("find stream video fail");
			return ;
		}
		System.out.println("find stream video succ.");


		// 得到video編碼格式
		// pCodecCtx = pFormatCtx.streams[videoStream].codec;
		/* 新版推薦替換方法 */
		pCodecCtx = avcodec_alloc_context3(null);
		result = avcodec_parameters_to_context(pCodecCtx, pFormatCtx.streams(videoStream).codecpar());
		if (result < 0)
			return ;
		av_codec_set_pkt_timebase(pCodecCtx, pFormatCtx.streams(videoStream).time_base());
		// step5: 得到解碼器
		pCodec = avcodec_find_decoder(pCodecCtx.codec_id());
		if (pCodec == null){
			System.out.println("find decoder fail" );
			return ;
		}
		System.out.println("find decoder succ");
		result = avcodec_open2(pCodecCtx, pCodec, (PointerPointer<Pointer>)null);
		if (result != 0){
			System.out.println("open codec fail");
			return ;
		}


		// step6: 申請原始資料幀 和 RGB幀記憶體
		pFrame = av_frame_alloc();
		pFrameRGB = av_frame_alloc();
		if (pFrame == null || pFrameRGB == null)
		{
			return ;
		}
		// int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx.width, pCodecCtx.height);
		int numBytes = av_image_get_buffer_size(AV_PIX_FMT_BGR24, pCodecCtx.width(), pCodecCtx.height(), 1);
		// 新版推薦替換函式
		// uint8_t* buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
		// avpicture_fill((AVPicture*)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pCodecCtx.width, pCodecCtx.height);
		BytePointer rgbData=new BytePointer(av_malloc(numBytes));
		av_image_fill_arrays(pFrameRGB.data(), pFrameRGB.linesize(), rgbData, AV_PIX_FMT_BGR24, pCodecCtx.width(), pCodecCtx.height(), 1);
		// 新版推薦替換函式


		int frameFinishsed = 0;
		packet = av_packet_alloc();
		i = 0;


		// step7: 建立格式轉化文字
		pSwxCtx = sws_getContext(
				pCodecCtx.width(), pCodecCtx.height(), pCodecCtx.pix_fmt(),
				pCodecCtx.width(), pCodecCtx.height(), AV_PIX_FMT_RGB24,
				SWS_BILINEAR, null, null, (DoublePointer)null);


		Mat image=new Mat(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);
				/* 新版推薦替換方法 */
				result = avcodec_send_packet(pCodecCtx, packet);
				if (result < 0) {
					System.out.println("Decode Error");
					return ;
				}
				result = avcodec_receive_frame(pCodecCtx, pFrame);
				if (result < 0 && result != -11) return  ;
				// 轉換
				sws_scale(pSwxCtx, pFrame.data(), pFrame.linesize(), 0, pCodecCtx.height(),pFrameRGB.data(), pFrameRGB.linesize());


				image.data(pFrameRGB.data(0));
				imshow("haha", image);
				if(waitKey(30)==27){
					break;
				}
			}


			// av_free_packet(packet);
			av_packet_unref(packet);
			// 新版推薦替換函式
		}


		avformat_close_input(pFormatCtx);
		av_packet_free(packet);
		// 新版推薦替換函式
	}


	public static void main(String[] args) throws Exception {
		FFmpegRead ffmpegRead=new FFmpegRead();
	}


}
AV_PIX_FMT_RGB24   改為  AV_PIX_FMT_BGR24 顏色就是正常的,因為opencv的顏色通道時BGR的,顯示時會偏綠