core/vidl_vil1/vidl_vil1_mpegcodec.cxx

Go to the documentation of this file.
00001 // This is core/vidl_vil1/vidl_vil1_mpegcodec.cxx
00002 #include "vidl_vil1_mpegcodec.h"
00003 #include <vidl_vil1/vidl_vil1_yuv_2_rgb.h>
00004 #include <vcl_cstring.h> // for memcpy()
00005 #include <vcl_iostream.h>
00006 #include <vcl_cassert.h>
00007 #include <vcl_cstdlib.h> // for vcl_strtol()
00008 #include <vul/vul_file.h>
00009 #include <vil1/vil1_image.h>
00010 #include <vil1/vil1_memory_image_of.h>
00011 #include <vil1/vil1_rgb_byte.h>
00012 #undef sprintf // Works around a bug in libintl.h
00013 #include <vcl_cstdio.h>
00014 
00015 extern "C" {
00016   // instead of #include <../libvo/video_out_internal.h>
00017   /*
00018    * video_out_internal.h
00019    * Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
00020    * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
00021    *
00022    * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
00023    * See http://libmpeg2.sourceforge.net/ for updates.
00024    *
00025    * mpeg2dec is free software; you can redistribute it and/or modify
00026    * it under the terms of the GNU General Public License as published by
00027    * the Free Software Foundation; either version 2 of the License, or
00028    * (at your option) any later version.
00029    *
00030    * mpeg2dec is distributed in the hope that it will be useful,
00031    * but WITHOUT ANY WARRANTY; without even the implied warranty of
00032    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00033    * GNU General Public License for more details.
00034    *
00035    * You should have received a copy of the GNU General Public License
00036    * along with this program; if not, write to the Free Software
00037    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00038    */
00039 
00040   extern uint32_t vo_mm_accel;
00041 
00042   int libvo_common_alloc_frames (vo_instance_t * instance, int width, int height,
00043                                  int frame_size,
00044                                  void (* copy) (vo_frame_t *, uint8_t **),
00045                                  void (* field) (vo_frame_t *, int),
00046                                  void (* draw) (vo_frame_t *));
00047   void libvo_common_free_frames (vo_instance_t * instance);
00048   vo_frame_t * libvo_common_get_frame (vo_instance_t * instance, int prediction);
00049 
00050 #define MODE_RGB  0x1
00051 #define MODE_BGR  0x2
00052 
00053   extern void (* yuv2rgb) (uint8_t * image, uint8_t * py,
00054                            uint8_t * pu, uint8_t * pv, int h_size, int v_size,
00055                            int rgb_stride, int y_stride, int uv_stride);
00056 
00057   void yuv2rgb_init (int bpp, int mode);
00058   int yuv2rgb_init_mmxext (int bpp, int mode);
00059   int yuv2rgb_init_mmx (int bpp, int mode);
00060   int yuv2rgb_init_mlib (int bpp, int mode);
00061 }
00062 
00063 // and now, for something completely different...
00064 // ultimately all these static functions are used to make
00065 // vo_vil_im_open, whose function pointer I will pass to
00066 // vidl_vil1_mpegcodec_helper.
00067 //
00068 /////////////////////////////////////////////////////////////////////
00069 // This copies the frame into the current frame buffer.
00070 // N.B. the decoder currently decodes the entire frame.
00071 // hence, the width gotten from the instance variable
00072 // below, the frame width. however, the width from
00073 // the request is the roi width.
00074 static void internal_draw_frame (vidl_vil1_mpegcodec_data * instance,
00075                                  vo_frame_t * frame,
00076                                  unsigned char * buf)
00077 {
00078   uint8_t *Y = frame->base[0];
00079   uint8_t *U = frame->base[1];
00080   uint8_t *V = frame->base[2];
00081   decode_request * p = instance->pending_decode;
00082 
00083   int c = 0;
00084   int w = instance->width;
00085 
00086 
00087   int roix = p->x0;
00088   int roiy = p->y0;
00089   int roiw = p->w;
00090   int roih = p->h;
00091 //int roixend = roix + p->w;
00092   int wh = w>>1;
00093 
00094   if (instance->output_format == vidl_vil1_mpegcodec_data::GREY)
00095   {
00096     // Recover in gray
00097     for (int i=roiy; i<(roiy+roih); ++i)
00098       for (int j=roix; j<(roix+roiw); ++j, ++c)
00099         buf[c]= Y[i*p->w+j];
00100   }
00101   else
00102   {
00103     // Recover in RGB
00104     for (int i=roiy; i<(roiy+roih); ++i)
00105       for (int j=roix; j<(roix+roiw); ++j, c+=3)
00106       {
00107         int arg = (i>>1)*(wh)+(j>>1);
00108         // this is assuming the chroma channels are half-size in each direction.
00109         vidl_vil1_yuv_2_rgb(Y[i*w+j],
00110                             U[arg],
00111                             V[arg],
00112                             &(buf[c]));
00113       }
00114   }
00115   return;
00116 }
00117 
00118 static int internal_setup (vo_instance_t * instance_,
00119                            int width,
00120                            int height,
00121                            void (* draw_frame) (vo_frame_t *))
00122 {
00123   vidl_vil1_mpegcodec_data * instance;
00124 
00125   instance = (vidl_vil1_mpegcodec_data *) instance_;
00126 
00127   instance->close = libvo_common_free_frames;
00128   instance->get_frame = libvo_common_get_frame;
00129   instance->width = width;
00130   instance->height = height;
00131 
00132   //sanity check.
00133   //i am assuming here that pending_decode has already been set
00134   decode_request * p = instance->pending_decode;
00135   if ((p->x0+p->w)>width) p->w = width - p->x0;
00136   if ((p->y0+p->h)>height) p->h = height - p->y0;
00137 
00138   int hh = height>>1;
00139   vcl_sprintf(instance->header, "P5\n\n%d %d\n255\n", width, hh * 3);
00140   return libvo_common_alloc_frames ((vo_instance_t *) instance,
00141                                     width,
00142                                     height,
00143                                     sizeof (vo_frame_t),
00144                                     0, 0, draw_frame);
00145 }
00146 
00147 static void vil1_im_draw_frame (vo_frame_t * frame)
00148 {
00149   vidl_vil1_mpegcodec_data * instance;
00150 
00151   instance = (vidl_vil1_mpegcodec_data *) frame->instance;
00152   int n = ++(instance->framenum);
00153   if ( n < 0)
00154     return;
00155 
00156   decode_request * p = instance->pending_decode;
00157   if (!p)
00158   {
00159     vcl_cerr << __FILE__ ": vil1_im_draw_frame(): decode request was never set\n";
00160     return;
00161   }
00162 
00163   frame_buffer * fb = instance->buffers;
00164 
00165   if (p->rt == decode_request::SEEK)
00166   {
00167     if (instance->framenum == p->position )
00168       p->done = true;
00169 
00170     internal_draw_frame (instance, frame, fb->next(n));
00171   }
00172   else if (p->rt == decode_request::FILE_GRAB)
00173     internal_draw_frame (instance, frame, fb->next(n));
00174 
00175   return;
00176 }
00177 
00178 //another callback, called by helper class
00179 //after this is called, the client of this class
00180 //should set the decode request
00181 static int vil1_im_setup (vo_instance_t * instance, int width, int height)
00182 {
00183   return internal_setup (instance, width, height, vil1_im_draw_frame);
00184 }
00185 
00186 // this method is a callback, called by the helper class
00187 vo_instance_t * vo_vil_im_open (void)
00188 {
00189   vidl_vil1_mpegcodec_data * instance;
00190 
00191   instance = new vidl_vil1_mpegcodec_data;
00192 
00193   //set call backs
00194   instance->setup = vil1_im_setup;
00195   instance->framenum = -2;
00196   return (vo_instance_t *) instance;
00197 }
00198 
00199 //////////////////////////////////////////////////////////////////////////////
00200 vidl_vil1_mpegcodec::vidl_vil1_mpegcodec()
00201 {
00202   decoder_ = 0;
00203   buffers_ = new frame_buffer;
00204   inited = false;
00205   set_number_frames(-1);
00206 }
00207 
00208 vidl_vil1_mpegcodec::~vidl_vil1_mpegcodec()
00209 {
00210   vcl_cout << "vidl_vil1_mpegcodec::~vidl_vil1_mpegcodec. entering\n";
00211   if (decoder_) decoder_->print();
00212   buffers_->print();
00213   vcl_cout << "first frame number in memory is: " << buffers_->first_frame_num() << vcl_endl;
00214   delete buffers_;
00215   if (decoder_) delete decoder_;
00216 
00217   vcl_cout << "vidl_vil1_mpegcodec::~vidl_vil1_mpegcodec. exiting\n";
00218 }
00219 
00220 void
00221 vidl_vil1_mpegcodec::set_grey_scale(bool grey)
00222 {
00223   if (!decoder_)
00224   {
00225     vcl_cout << "vidl_vil1_mpegcodec::set_gray_scale. need to load file first.\n";
00226     return;
00227   }
00228 
00229   if (grey) decoder_->output_->output_format = vidl_vil1_mpegcodec_data::GREY;
00230   else decoder_->output_->output_format = vidl_vil1_mpegcodec_data::RGB;
00231 }
00232 
00233 //this method is SUPPOSED to parse the header and determine stuff
00234 //like height, width, number of frames, bits per pixel, etc. however,
00235 //i don't have the time right now to write such a header. hopefully it
00236 //will be done someday.
00237 vidl_vil1_codec_sptr vidl_vil1_mpegcodec::load(vcl_string const& fname, char  /*mode*/)
00238 {
00239   //just running probe here just to be safe,
00240   //though the client is supposed to run this anyway before
00241   //using this method.
00242   if (this->probe(fname))
00243   {
00244     decoder_ = new vidl_vil1_mpegcodec_helper(vo_vil_im_open,
00245                                               fname,
00246                                               buffers_);
00247     return this;
00248   }
00249   return 0;
00250 }
00251 
00252 bool
00253 vidl_vil1_mpegcodec::get_section(int position,
00254                                  void* ib,
00255                                  int x0,
00256                                  int y0,
00257                                  int width,
00258                                  int height) const
00259 {
00260   assert(inited == true);
00261   assert(x0+width  <= this->width());
00262   assert(y0+height <= this->height());
00263 
00264   //CASE 1:
00265   //if a frame is requested that is prior to what is
00266   //in the frame buffer, need to rewind and start all over.
00267   if (position < buffers_->first_frame_num())
00268   {
00269     decode_request req;
00270     req.rt = decode_request::REWIND;
00271     req.position = position;
00272     req.x0 = x0;
00273     req.y0 = y0;
00274     req.w = width;
00275     req.h = height;
00276     req.done = false;
00277     decoder_->execute(&req);
00278     buffers_->reset();
00279 
00280     req.rt = decode_request::SEEK;
00281 
00282     decoder_->execute(&req);
00283   }
00284   //CASE 2:
00285   //the requested frame is beyond what is in the frame buffer
00286   else if (position > decoder_->get_last_frame())
00287   {
00288     decode_request req;
00289     req.rt = decode_request::SEEK;
00290     req.position = position;
00291     req.x0 = x0;
00292     req.y0 = y0;
00293     req.w = width;
00294     req.h = height;
00295     req.done = false;
00296     decoder_->execute(&req);
00297   }
00298   //CASE 3: position requested is actually in frame buffer
00299   else
00300   {
00301     if ((decoder_->get_last_frame() - position) < 10)
00302     {
00303       decode_request req;
00304       req.rt = decode_request::FILE_GRAB;
00305       req.position = position;
00306       req.x0 = x0;
00307       req.y0 = y0;
00308       req.w = width;
00309       req.h = height;
00310       req.done = false;
00311 
00312       //grab a couple of times. why? because from experiment, this seems
00313       //to be the minimal number necessary to grab at least two frames.
00314       //this varies, of course, with roi size, stream protocol, etc.
00315       decoder_->execute(&req);
00316       decoder_->execute(&req);
00317     }
00318   }
00319 
00320   unsigned char * buf = buffers_->get_buff(position);
00321   vcl_memcpy(ib,(void *) buf,((this->get_bytes_pixel())*width*height));
00322 
00323   return true;
00324 }
00325 
00326 bool
00327 vidl_vil1_mpegcodec::probe(vcl_string const& fname)
00328 {
00329   vcl_string exten = vul_file::extension(fname);
00330   bool isthere = vul_file::exists(fname) && (exten == ".mpeg" ||
00331                                              exten == ".mpe"  ||
00332                                              exten == ".mpg"  ||
00333                                              exten == ".mp2"  ||
00334                                              exten == ".mp1");
00335 
00336   return isthere;
00337 }
00338 
00339 void
00340 vidl_vil1_mpegcodec::set_demux_video()
00341 {
00342   decoder_->demux_track_ = 0xe0;
00343 }
00344 
00345 void
00346 vidl_vil1_mpegcodec::set_pid(vcl_string pid)
00347 {
00348   decoder_->demux_pid_ = vcl_strtol(pid.c_str(),0,16);
00349 }
00350 
00351 //called by load method
00352 //assumed the helper is already instantiated
00353 bool
00354 vidl_vil1_mpegcodec::init()
00355 {
00356   if (inited) return true;
00357 
00358   //decode at least one
00359   //first make a proper request
00360   //this is done to get the true width and height
00361   //and total number of frames, all without
00362   //have to read the header.
00363   decode_request req;
00364   req.rt = decode_request::SKIP;
00365   req.position = 0;
00366   req.x0 = 0;
00367   req.y0 = 0;
00368   req.w = 1000;
00369   req.h = 1000;
00370   req.done = false;
00371 
00372   decoder_->init();
00373 
00374   //if the total number of frames is not manually
00375   //entered by this point, then decode the whole
00376   //bloody thing till the end. else, just decode
00377   //once to get the true width and height.
00378   if (this->length() == -1)
00379   {
00380     while (decoder_->execute(&req) != -1);
00381     this->set_number_frames(decoder_->get_last_frame());
00382   }
00383   else decoder_->execute(&req);
00384 
00385   req.rt = decode_request::REWIND;
00386   decoder_->execute(&req);
00387 
00388   //initialize codec members
00389   //first, truncate to our frame
00390   int w = decoder_->get_width();
00391   int h = decoder_->get_height();
00392 
00393   //i need to play nicey-nicey and set these variables
00394   //from the base class.
00395   int b;
00396   this->set_width(w);
00397   this->set_height(h);
00398   if (decoder_->get_format() == vidl_vil1_mpegcodec_data::RGB)
00399     b=24;
00400   else // if (decoder_->get_format() == vidl_vil1_mpegcodec_data::GREY)
00401     b=8;
00402   set_bits_pixel(b);
00403 
00404   //allocate memory for frame buffer now
00405   buffers_->init(w,h,b);
00406 
00407   //get at least 30 frames in there
00408   req.rt = decode_request::SEEK;
00409   req.position = 20;
00410   req.x0 = 0;
00411   req.y0 = 0;
00412   req.w = w;
00413   req.h = h;
00414   req.done = false;
00415 
00416   decoder_->execute(&req);
00417 
00418   //clean up
00419   inited = true;
00420   return true;
00421 }
00422 
00423 #if 0
00424 //here for reference.
00425 //this actually describes how to get a
00426 //vil1_image from these char * buffers.
00427 
00428 vil1_image *
00429 vidl_vil1_mpegcodec::get_image(int frame_position,
00430                                int x0,
00431                                int y0,
00432                                int width,
00433                                int height)
00434 {
00435   vil1_image * frame = 0;
00436 
00437   int indy = width * height * this->get_bytes_pixel();
00438   unsigned char ib[indy];
00439   this->get_section(frame_position,(void*)ib,x0,y0,width,height);
00440 
00441   if (decoder_->get_format() == vidl_vil1_mpegcodec_data::GREY)
00442     frame = new vil1_memory_image_of<unsigned char >(&ib[0],this->width(),this->height());
00443   else
00444   {
00445     int w = this->width();
00446     int h = this->height();
00447     vil1_rgb_byte bites[w*h];
00448     int c=0;
00449     for (int i=0; i<(w*h); i++,c+=3)
00450       bites[i] = vil1_rgb_byte(ib[c],ib[c+1],ib[c+2]);
00451     frame = new vil1_memory_image_of<vil1_rgb_byte >(&bites[0],w,h);
00452   }
00453   return frame;
00454 }
00455 #endif // 0

Generated on Tue Dec 2 05:09:13 2008 for core/vidl_vil1 by  doxygen 1.5.1