00001 package org.hfbk.vid;
00002
00003 import java.nio.ByteBuffer;
00004
00005 import net.sf.ffmpeg_java.AVCodecLibrary;
00006 import net.sf.ffmpeg_java.SWScaleLibrary;
00007 import net.sf.ffmpeg_java.AVCodecLibrary.AVCodecContext;
00008 import net.sf.ffmpeg_java.AVCodecLibrary.AVFrame;
00009 import net.sf.ffmpeg_java.AVFormatLibrary.AVPacket;
00010
00011 import org.hfbk.util.Sleeper;
00012 import org.hfbk.vis.Prefs;
00013
00014 import com.sun.jna.Pointer;
00015 import com.sun.jna.ptr.IntByReference;
00016
00026 class AVVideoThread extends AVStreamThread{
00027
00028 final static int VIDEO_BUFFER=0x2FFFF;
00029
00030 AVFrame frame, frameRGB;
00031
00032 int width, height, frameBytes;
00033
00034 final int pix_fmt = AVCodecLibrary.PIX_FMT_RGB24;
00035
00036 int time;
00037
00038 Pointer swscaler;
00039
00041 ByteBuffer out;
00042
00043 public AVVideoThread(AVCodecContext ctx, int maxPixels) {
00044 super("AVVideoThread", ctx,VIDEO_BUFFER);
00045
00046 setDaemon(true);
00047 setPriority(Thread.MIN_PRIORITY+2);
00048
00049 width = ctx.width;
00050 height = ctx.height;
00051
00052 while (width*height>maxPixels){
00053 width/=2; height/=2;
00054 }
00055
00056 frame = AV.CODEC.avcodec_alloc_frame();
00057 frameRGB = AV.CODEC.avcodec_alloc_frame();
00058
00059 if (frame == null || frameRGB == null)
00060 throw new RuntimeException("Could not allocate frames");
00061
00062
00063
00064 frameBytes = AV.CODEC.avpicture_get_size(pix_fmt, width, height);
00065 final Pointer buffer = AV.UTIL.av_malloc(frameBytes);
00066 if (buffer == null)
00067 throw new RuntimeException("Could not allocate frame buffers");
00068
00069
00070 AV.CODEC.avpicture_fill(frameRGB, buffer, pix_fmt, width, height);
00071
00072
00073 synchronized(AV.SWSCALE){
00074 swscaler = AV.SWSCALE.sws_getContext(ctx.width, ctx.height,
00075 ctx.pix_fmt, width, height,
00076 pix_fmt, SWScaleLibrary.SWS_POINT, null, null, null);
00077 }
00078 if (swscaler==null)
00079 throw new RuntimeException("Could not open swscaler.");
00080 }
00081
00082
00083 ByteBuffer decodeVideo(AVPacket packet){
00084
00085
00086 final IntByReference frameFinished = new IntByReference();
00087
00088 AV.CODEC.avcodec_decode_video(ctx, frame, frameFinished, packet.data, packet.size);
00089
00090
00091
00092 if (frameFinished.getValue() != 0) {
00093
00094
00095 convertToRGB(frame, frameRGB);
00096
00097
00098 return frameRGB.data0.getByteBuffer(0, frameBytes);
00099 }
00100 return null;
00101 }
00102
00103
00104
00105
00106
00107 public void run() {
00108 AVPacket packet;
00109 while(running){
00110
00111 packet=null;
00112 while (running && ( !playing || (packet=poll())==null && !finished) )
00113 Sleeper.sleep(2);
00114
00115 if (packet==null) break;
00116
00117
00118
00119 out=decodeVideo(packet);
00120
00121 int dt=(int)packet.pts-time+40;
00122
00123 tick((int)packet.pts);
00124
00125 free(packet);
00126
00127 if(dt>0) Sleeper.sleep(dt);
00128 }
00129
00130 close();
00131 }
00132
00133 protected void close(){
00134 if(Prefs.current.debug) System.out.println("AVVideo finished.");
00135 super.close();
00136 synchronized(AV.UTIL){
00137 if(frameRGB.data0!=null)
00138 AV.UTIL.av_free(frameRGB.data0);
00139 AV.UTIL.av_free(frameRGB.getPointer());
00140 AV.UTIL.av_free(frame.getPointer());
00141 }
00142 synchronized (AV.SWSCALE) {AV.SWSCALE.sws_freeContext(swscaler);}
00143 if(Prefs.current.debug) System.out.println("AVVideo down!");
00144 }
00145
00146
00147
00148
00149 int convertToRGB(AVFrame src, AVFrame dst) {
00150 Pointer[] id = src.getPointer().getPointerArray(0, 4);
00151 Pointer[] od = dst.getPointer().getPointerArray(0, 4);
00152 int[] src_linesize = src.getPointer().getIntArray(4*Pointer.SIZE, 4);
00153 int[] dst_linesize = dst.getPointer().getIntArray(4*Pointer.SIZE, 4);
00154
00155 return AV.SWSCALE.sws_scale(swscaler, id, src_linesize, 0, ctx.height, od, dst_linesize);
00156 }
00157 }