VisClient/org/hfbk/vid/AVVideoThread.java

Go to the documentation of this file.
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; // original and rgb resampled framebuffer
00031         
00032         int width, height, frameBytes;
00033         
00034         final int pix_fmt = AVCodecLibrary.PIX_FMT_RGB24;
00035         
00036         int time;
00037         
00038         Pointer swscaler; //holds rgb conversion engine
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(); // to hold one frame
00057                 frameRGB = AV.CODEC.avcodec_alloc_frame(); // to hold rgb converted frame
00058                 
00059                 if (frame == null || frameRGB == null)
00060                         throw new RuntimeException("Could not allocate frames");
00061 
00062                 // the frame buffer itself is created by the codec.
00063                 // but we need to build a buffer for our RGB converted frame.
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                 // assign buffer to frameRGB
00070                 AV.CODEC.avpicture_fill(frameRGB, buffer, pix_fmt, width, height);      
00071         
00072                 //build software scaler for rgb conversion
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         /* decode one video AVPacket */
00083         ByteBuffer decodeVideo(AVPacket packet){
00084                 // a call-by-reference parameter from native code
00085                 // just give us back one integer
00086                 final IntByReference frameFinished = new IntByReference();
00087 
00088                 AV.CODEC.avcodec_decode_video(ctx, frame, frameFinished, packet.data, packet.size);
00089                 
00090                 // one packet equals one frame but could take 
00091                 // more than pne before they could be decoded.
00092                 if (frameFinished.getValue() != 0) {
00093                         
00094                         // Convert the image from its native color format to RGB
00095                         convertToRGB(frame, frameRGB);
00096                                         
00097                         // return the frame RGB data
00098                         return frameRGB.data0.getByteBuffer(0, frameBytes);
00099                 }
00100                 return null;
00101         }
00102 
00103         
00104         /* decoding main loop. polls packets from the videoQueue
00105          * and decodes them to videoOut buffer. speed is limited
00106          * by the media time advanced via getFrame(). */
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                         //we are told to stop 
00117                         //or the stream is finished and the queue all used up.
00118                         
00119                         out=decodeVideo(packet);
00120                         
00121                         int dt=(int)packet.pts-time+40;
00122                         
00123                         tick((int)packet.pts); //fire a tick to synchronize others
00124                         
00125                         free(packet); //put packet to recycling                         
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         /* convert a frame from native to RGB color format 
00147          * via libav's swscale software scaler. this should be 
00148          * replaced by gpu shader if available. */
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 }

Generated on Tue Apr 7 17:57:20 2009 for visclient by  doxygen 1.5.1