Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

oxp_mpeg_codec.cxx

Go to the documentation of this file.
00001 // This is oxl/oxp/oxp_mpeg_codec.cxx
00002 #include "oxp_mpeg_codec.h"
00003 //:
00004 //  \file
00005 
00006 extern "C" {
00007   typedef unsigned char uint8_t;
00008   typedef unsigned int uint32_t;
00009 #define this c_this
00010 #include <mpeg2dec/video_out.h>
00011 #include <mpeg2dec/mpeg2.h>
00012 #include <mpeg2dec/mm_accel.h>
00013 #undef this
00014 }
00015 
00016 #include <vcl_cstdio.h>
00017 #include <vcl_cassert.h>
00018 #include <vcl_cstdlib.h>
00019 #include <vcl_cstring.h>
00020 #include <vcl_string.h>
00021 #include <vcl_iostream.h>
00022 
00023 #include <vul/vul_file.h>
00024 
00025 #include <oxp/oxp_yuv_to_rgb.h>
00026 #include <oxp/oxp_bunch_of_files.h>
00027 #include <oxp/oxp_vob_frame_index.h>
00028 
00029 static bool verbose = false;
00030 
00031 // predeclare mpeg callbacks
00032 static void my_draw(vo_frame_t *frame);
00033 static void my_field(vo_frame_t *, int);
00034 static vo_frame_t *my_get_frame(vo_instance_t *self, int flags);
00035 static void my_close(vo_instance_t *self);
00036 static int my_setup(vo_instance_t *self, int width, int height);
00037 
00038 // and other statics
00039 static int demux(oxp_mpeg_codec_data* impl, unsigned char const *buf, unsigned char const *end, int flags);
00040 
00041 struct oxp_mpeg_codec_data : vo_instance_t {
00042   struct decode_request {
00043     int frame;
00044     int x0, y0, w, h;
00045     unsigned char* buf;
00046     bool done;
00047   };
00048   enum output_format_t {
00049     grey, rgb
00050   };
00051   struct frame_plus_index : public vo_frame_t {
00052     int frame;
00053   };
00054 
00055   oxp_bunch_of_files fp;
00056   oxp_vob_frame_index idx;
00057   int w;
00058   int h;
00059   int frame_number;
00060   int demux_track;
00061   int demux_pid;
00062   output_format_t output_format;
00063   int ring_buffer_pos;
00064   frame_plus_index *ring_buffer[8];
00065   uint32_t accel;    // acceleration?
00066   mpeg2dec_t decoder;
00067   unsigned char (*ppm_frame)[3];
00068   decode_request* pending_decode;
00069 
00070   // oxp_mpeg_codec_data();
00071 
00072   bool seek_to_iframe_before(int desired);
00073   frame_plus_index *make_frame();
00074   void convert_frame(frame_plus_index* frame, decode_request* p);
00075   int decode_mpeg2(unsigned char const *start, unsigned char const *end);
00076   void destroy_frame(vo_frame_t *frame);
00077   void draw_grey(unsigned char *frame);
00078   void draw(unsigned char (*frame)[3]);
00079 
00080   void decode_at_least_one();
00081   bool decode_until_desired(int f,
00082                             void* buf,
00083                             int bbox_x0,
00084                             int bbox_y0,
00085                             int bbox_w,
00086                             int bbox_h);
00087 };
00088 
00089 //-----------------------------------------------------------------------------
00090 oxp_mpeg_codec::oxp_mpeg_codec()
00091 {
00092   impl_ = new oxp_mpeg_codec_data;
00093 
00094   impl_->pending_decode = 0;
00095   impl_->vo_instance_t::setup = &my_setup;
00096   impl_->vo_instance_t::close = &my_close;
00097   impl_->vo_instance_t::get_frame = &my_get_frame;
00098 
00099   for (int i=0; i<8; ++i)
00100     impl_->ring_buffer[i] = 0;
00101   impl_->ring_buffer_pos = 0;
00102 
00103   impl_->accel = /* MM_ACCEL_X86_MMX | */ MM_ACCEL_MLIB;
00104   vo_accel(impl_->accel);
00105 
00106   // initialize decoder.
00107   mpeg2_init(&impl_->decoder, impl_->accel, impl_);
00108 
00109   impl_->ppm_frame = 0;
00110   impl_->demux_track = 0;
00111   impl_->demux_pid = 0;
00112   impl_->output_format = oxp_mpeg_codec_data::rgb;
00113 }
00114 
00115 bool oxp_mpeg_codec_data::seek_to_iframe_before(int frame)
00116 {
00117   int start_frame_index;
00118   int lba = idx.frame_to_lba_of_prev_I_frame(frame, &start_frame_index);
00119   // --lba; // lba's start from 1?
00120   typedef oxp_bunch_of_files::offset_t index_t;
00121   index_t byte = index_t(lba) * 2048;
00122 
00123   if (verbose)
00124     vcl_cerr << __FILE__ << ": seek_to_iframe_before: Frame " << frame
00125              << " -> Start at closest frame " << start_frame_index
00126              << ", LBA " << lba << ", byte " << byte << '\n';
00127   if (lba < 0)
00128   {
00129     vcl_cerr << __FILE__ << ": ERROR!\n";
00130     return false;
00131   }
00132   if (!fp.seek(byte))
00133   {
00134     vcl_cerr << "oxp_mpeg_codec_data::seek_to_iframe_before: ERROR!\n";
00135     return false;
00136   }
00137   frame_number = start_frame_index-1; // This is the frame we have "just finished decoding"...
00138   return true;
00139 }
00140 
00141 //: Decode at least one frame.
00142 // Will call static routines below:
00143 //   my_setup
00144 //   my_get_frame
00145 //   my_draw
00146 void oxp_mpeg_codec_data::decode_at_least_one()
00147 {
00148   int starting_frame_number = frame_number;
00149   int n;
00150   unsigned char buf[2048];
00151   while ((n = fp.read(buf, sizeof buf)) > 0) {
00152     unsigned char* start = &buf[0];
00153     unsigned char* end = start + n;
00154     if (demux_track)
00155     {
00156       if (::demux(this, start, end, 0))
00157         return; // hit program_end_code
00158     }
00159     else if (demux_pid)
00160       vcl_abort();
00161     else
00162       // plain old
00163       this->decode_mpeg2(start, end);
00164 
00165     if (frame_number > starting_frame_number)
00166       return;
00167   }
00168 }
00169 
00170 //: Run mpeg till you find frame f.
00171 // Return false if that ain't gonna happen.
00172 bool oxp_mpeg_codec_data::decode_until_desired(int f,
00173                                                void* buf,
00174                                                int bbox_x0,
00175                                                int bbox_y0,
00176                                                int bbox_w,
00177                                                int bbox_h)
00178 {
00179   decode_request r;
00180   r.frame = f;
00181   r.buf = (unsigned char*)buf;
00182   r.x0 = bbox_x0;
00183   r.y0 = bbox_y0;
00184   r.w = bbox_w;
00185   r.h = bbox_h;
00186   r.done = false;
00187 
00188   // Check the ring buffer to see if any in there...
00189   for (int i = 0; i < 8; ++i)
00190     if (ring_buffer[i] && ring_buffer[i]->frame == f)
00191     {
00192       if (verbose)
00193         vcl_cerr << __FILE__ << ": decode_until_desired: Found frame " << f << " in ring buffer\n";
00194       convert_frame(ring_buffer[i], &r);
00195       r.done = true;
00196       return true;
00197     }
00198 
00199   // Not in ring buffer, only possible if f < frame_number
00200   if (f <= frame_number)
00201   {
00202     if (verbose)
00203       vcl_cerr << __FILE__ << ": decode_until_desired: Need to seek for " << f << '\n';
00204     return false;
00205   }
00206 
00207   // Not decoded, seek for it
00208   pending_decode = &r;
00209 
00210   unsigned char fbuf[2048];
00211   int n;
00212   while ((n = fp.read(fbuf, sizeof fbuf)) > 0)
00213   {
00214     unsigned char* start = &fbuf[0];
00215     unsigned char* end = start + n;
00216     if (demux_track)
00217     {
00218       if (::demux(this, start, end, 0))
00219         return r.done;  // hit program_end_code
00220     }
00221     else if (demux_pid)
00222       vcl_abort();
00223     else
00224       // plain old
00225       this->decode_mpeg2(start, end);
00226 
00227     if (r.done)
00228     {
00229       pending_decode = 0;
00230       return true;
00231     }
00232   }
00233 
00234   return false;
00235 }
00236 
00237 int oxp_mpeg_codec_data::decode_mpeg2(unsigned char const *start, unsigned char const *end)
00238 {
00239   return mpeg2_decode_data(&decoder, const_cast<uint8_t*>(start), const_cast<uint8_t*>(end));
00240 }
00241 
00242 ////// Callbacks to place in the vo_instance_t's struct.
00243 
00244 static
00245 int my_setup(vo_instance_t *self, int width, int height)
00246 {
00247   if (verbose)
00248     vcl_cerr << __FILE__ << ": setup(" << width << ", " << height << ")\n";
00249   oxp_mpeg_codec_data *impl = (oxp_mpeg_codec_data*)self;
00250   impl->w = width;
00251   impl->h = height;
00252 
00253   impl->frame_number = 0;
00254 
00255   impl->ppm_frame = (uint8_t (*)[3]) vcl_malloc(3 * width * height);
00256 
00257   return 0;
00258 }
00259 
00260 static
00261 void my_close(vo_instance_t *self)
00262 {
00263   if (verbose) vcl_cerr << __FILE__ << ": close()\n";
00264   oxp_mpeg_codec_data *impl = (oxp_mpeg_codec_data*)self;
00265 
00266   vcl_free(impl->ppm_frame);
00267 }
00268 
00269 static
00270 vo_frame_t *
00271 my_get_frame(vo_instance_t *self, int flags)
00272 {
00273 #if 0
00274 #define VO_TOP_FIELD 1
00275 #define VO_BOTTOM_FIELD 2
00276 #define VO_BOTH_FIELDS (VO_TOP_FIELD | VO_BOTTOM_FIELD)
00277 #define VO_PREDICTION_FLAG 4
00278 #endif
00279   if (verbose)
00280     vcl_cerr << __FILE__ << ": get(" << flags << ")\n";
00281   oxp_mpeg_codec_data *impl = (oxp_mpeg_codec_data*)self;
00282 
00283   if (! impl->ring_buffer[impl->ring_buffer_pos])
00284     impl->ring_buffer[impl->ring_buffer_pos] = impl->make_frame();
00285 
00286   vo_frame_t *frame = impl->ring_buffer[impl->ring_buffer_pos ++];
00287   if (impl->ring_buffer_pos >= 8)
00288     impl->ring_buffer_pos = 0;
00289 
00290   return frame;
00291 }
00292 
00293 // called by my_get_frame callback to make space in the ring buffer
00294 oxp_mpeg_codec_data::frame_plus_index*
00295 oxp_mpeg_codec_data::make_frame()
00296 {
00297   frame_plus_index *frame = (frame_plus_index*) vcl_malloc(sizeof(frame_plus_index));
00298   if (verbose)
00299     vcl_cerr << __FILE__ << ": make_frame() : frame = " << frame << '\n';
00300   frame->base[0] = (uint8_t*) vcl_malloc(    w * h    );
00301   frame->base[1] = (uint8_t*) vcl_malloc((w>>1)*(h>>1));
00302   frame->base[2] = (uint8_t*) vcl_malloc((w>>1)*(h>>1));
00303   frame->copy = 0; // my_copy;
00304   frame->field = my_field;
00305   frame->draw = my_draw;
00306   frame->instance = this;
00307   frame->frame = -1;
00308   return frame;
00309 }
00310 
00311 #if 0
00312 static
00313 void my_copy(vo_frame_t *f, uint8_t **b)
00314 {
00315   if (verbose) vcl_printf("my_copy()\n");
00316 }
00317 #endif
00318 
00319 static
00320 void my_field(vo_frame_t *, int)
00321 {
00322   if (verbose) vcl_cout << "my_field()\n";
00323 }
00324 
00325 static
00326 void my_draw(vo_frame_t *frame_p)
00327 {
00328   if (verbose)
00329     vcl_cout << "draw: frame = " << frame_p << "\nmy_draw()\n";
00330   oxp_mpeg_codec_data *impl = (oxp_mpeg_codec_data*)frame_p->instance;
00331   oxp_mpeg_codec_data::frame_plus_index* frame =
00332     static_cast<oxp_mpeg_codec_data::frame_plus_index*>(frame_p);
00333 
00334   ++impl->frame_number;
00335   frame->frame = impl->frame_number;
00336 
00337   oxp_mpeg_codec_data::decode_request* p = impl->pending_decode;
00338   if (!p)
00339     // nothing to decode, return.
00340     return;
00341 
00342   // got pending_decode from decode_until_desired
00343   if (p->frame == impl->frame_number)
00344   {
00345     if (verbose)
00346       vcl_cerr << __FILE__ << ": Found " << impl->frame_number << '\n';
00347     impl->convert_frame(frame, p);
00348     p->done = true;
00349   }
00350   else if (verbose)
00351   {
00352     if (impl->frame_number < p->frame)
00353       vcl_cerr << __FILE__ << ": Skipping " << impl->frame_number << " waiting for " << p->frame << '\n';
00354     else
00355       vcl_cerr << __FILE__ << ": Queuing " << impl->frame_number << " having got " << p->frame << '\n';
00356   }
00357 }
00358 
00359 void oxp_mpeg_codec_data::convert_frame(frame_plus_index* frame,
00360                                         decode_request* p)
00361 {
00362   // base[0] : luminance Y
00363   // base[1] : chroma 1  U
00364   // base[2] : chroma 2  V
00365   uint8_t *Y = frame->base[0];
00366   uint8_t *U = frame->base[1];
00367   uint8_t *V = frame->base[2];
00368 
00369   if (this->output_format == oxp_mpeg_codec_data::grey)
00370   {
00371     // Recover in gray
00372     //int w = this->w;
00373     //int h = this->h;
00374     //unsigned char (*ppm_frame)[3] = this->ppm_frame;
00375 
00376     int c = 0;
00377     for (int i=p->y0; i<p->h; ++i)
00378       for (int j=p->x0; j<p->w; ++j, ++c)
00379         // this is assuming the chroma channels are half-size in each direction.
00380         p->buf[c]= Y[i*p->w+j];
00381   }
00382   else
00383   {
00384     // Recover in RGB
00385     //int w = this->w;
00386     //int h = this->h;
00387 
00388     int c = 0;
00389     for (int i=p->y0; i<p->h; ++i)
00390       for (int j=p->x0; j<p->w; ++j, c+=3)
00391         // this is assuming the chroma channels are half-size in each direction.
00392         oxp_yuv_to_rgb(Y[i*w+j],
00393                        U[(i>>1)*(p->w>>1)+(j>>1)],
00394                        V[(i>>1)*(p->w>>1)+(j>>1)],
00395                        &p->buf[c]);
00396   }
00397 }
00398 
00399 
00400 void oxp_mpeg_codec_data::destroy_frame(vo_frame_t *frame)
00401 {
00402   assert(frame->instance == this);
00403   vcl_free(frame->base[0]); frame->base[0] = (uint8_t*)0xDEADBEEF;
00404   vcl_free(frame->base[1]); frame->base[1] = (uint8_t*)0xDEADBEEF;
00405   vcl_free(frame->base[2]); frame->base[2] = (uint8_t*)0xDEADBEEF;
00406   vcl_free(frame);
00407 }
00408 
00409 //-----------------------------------------------------------------------------
00410 oxp_mpeg_codec::~oxp_mpeg_codec()
00411 {
00412   if (impl_)
00413   {
00414     // close();
00415     vcl_cerr << "oxp_mpeg_codec: WARNING: deleting before close() was called\n";
00416     // You can't call close from within here because it may be being destroyed
00417     // statically, and the mpeg2_close call will segv.
00418     // So the options are segv or unflushed input.  segv is
00419     // incontrovertibly wrong, so we make sure that doesn't happen.
00420     for (int i=0; i<8; ++i)
00421       if (impl_->ring_buffer[i])
00422       {
00423         impl_->destroy_frame(impl_->ring_buffer[i]);
00424         impl_->ring_buffer[i] = 0;
00425       }
00426 
00427     delete impl_;
00428     impl_ = 0;
00429   }
00430 }
00431 
00432 //-----------------------------------------------------------------------------
00433 void oxp_mpeg_codec::close()
00434 {
00435   if (impl_)
00436   {
00437     // destroy decoder.
00438     mpeg2_close(&impl_->decoder);
00439 
00440     // close output object.
00441     vo_close(impl_);
00442 
00443     for (int i=0; i<8; ++i)
00444       if (impl_->ring_buffer[i])
00445       {
00446         impl_->destroy_frame(impl_->ring_buffer[i]);
00447         impl_->ring_buffer[i] = 0;
00448       }
00449 
00450     delete impl_;
00451     impl_ = 0;
00452   }
00453 }
00454 
00455 
00456 //-----------------------------------------------------------------------------
00457 bool oxp_mpeg_codec::get_section(int position, // position of the frame in the stream
00458                                  void* ib, // To receive the datas
00459                                  int x0, // starting x
00460                                  int y0, // starting y
00461                                  int xs, // row size
00462                                  int ys) const // col size
00463 {
00464   position += 2; //awf not sure if this is where the offset happens.
00465 
00466   const int FRAMES_TO_FFWD_RATHER_THAN_SEEK = 20;
00467   if (impl_->frame_number < position + 8 &&
00468       impl_->frame_number > position - FRAMES_TO_FFWD_RATHER_THAN_SEEK)
00469     if (impl_->decode_until_desired(position, ib, x0, y0, xs, ys))
00470       return true;
00471 
00472   // Didn't find the frame, seek and find.
00473   if (!impl_->seek_to_iframe_before(position))
00474     return false;
00475 
00476   return impl_->decode_until_desired(position, ib, x0, y0, xs, ys);
00477 }
00478 
00479 
00480 //: put_section not implemented yet.
00481 // We may need to change make_dib to
00482 // be able to put a section different
00483 // of the entire frame.
00484 int oxp_mpeg_codec::put_section(int position,
00485                                 void* ib,
00486                                 int x0, int y0,
00487                                 int xs, int ys)
00488 {
00489   vcl_cerr << "oxp_mpeg_codec::put_section not implemented\n";
00490   return -1;
00491 }
00492 
00493 //-----------------------------------------------------------------------------
00494 //: probe the file fname, open it as an MPEG file. If this works, close it and return true. False otherwise.
00495 
00496 bool oxp_mpeg_codec::probe(vcl_string const& fname)
00497 {
00498   if (verbose)
00499     vcl_cerr << "oxp_mpeg_codec::probe[" << fname << "]\n";
00500 
00501   // 1st try to open
00502   if (vcl_FILE* fp = vcl_fopen(fname.c_str(), "rb"))
00503   {
00504     unsigned int buf = 0xffffffffu;
00505     vcl_fread(&buf, 1, 4, fp);
00506     vcl_fclose(fp);
00507 
00508     bool ok = false;
00509     if (buf == 0x000001b3 || buf == 0xb3010000)
00510       ok=true; // mpeg
00511     if (buf == 0x000001ba || buf == 0xba010000)
00512       ok=true; // vob
00513 
00514     if (ok) // Try to find an idx
00515       return true;
00516   }
00517 
00518   vcl_string fn(fname);
00519 
00520   bool p = (vul_file::size((fn + ".lst").c_str()) > 0);
00521   if (verbose)
00522     vcl_cerr << "oxp_mpeg_codec::probe[" << fname << "] -> " << (p ? "true" : "false") << '\n';
00523   return p;
00524 }
00525 
00526 bool oxp_mpeg_codec::load(vcl_string const& fname, char mode)
00527 {
00528   // 1st try to open
00529   bool is_mpeg = false;
00530   bool is_vob = false;
00531   {
00532     vcl_FILE* fp = vcl_fopen(fname.c_str(), "rb");
00533     if (fp)
00534     {
00535       unsigned int buf = 0xffffffffu;
00536       vcl_fread(&buf, 1, 4, fp);
00537       vcl_fclose(fp);
00538 
00539       if (buf == 0x000001b3 || buf == 0xb3010000)
00540         is_mpeg = true; // mpeg
00541       if (buf == 0x000001ba || buf == 0xba010000)
00542         is_vob = true; // vob
00543     }
00544   }
00545 
00546   if (is_mpeg || is_vob)
00547   {
00548     impl_->fp.open_1(fname.c_str());
00549     impl_->decode_at_least_one();
00550 
00551     // Try to find an idx
00552     char buf[1024];
00553     vcl_strcpy(buf, fname.c_str());
00554     char* p = vcl_strrchr(buf, '.');
00555     if (!p) // No . in filename
00556       p = buf + vcl_strlen(buf)-1;
00557     vcl_strcpy(p, ".idx");
00558     vcl_cerr << "Trying index file [" << buf << "] ... ";
00559     if (vul_file::size(buf) > 0)
00560     {
00561       vcl_cerr << " loading ...";
00562       impl_->idx.load(buf);
00563     }
00564     else
00565     {
00566       vcl_cerr << " not present, will not be able to seek\n";
00567       impl_->idx.add(0, 0);
00568     }
00569 
00570     // Set demux if vob
00571     impl_->demux_track = is_vob ? 0xe0 : 0;
00572   }
00573   else
00574   {
00575     // Open fname, if a vob, set_demux
00576     vcl_string fn = fname;
00577 
00578     impl_->fp.open((fn + ".lst").c_str());
00579 
00580     impl_->decode_at_least_one();
00581 
00582     impl_->idx.load((fn + ".idx").c_str());
00583 
00584     impl_->demux_track = 0xe0;
00585   }
00586 
00587   return true;
00588 }
00589 
00590 //: Call this before calling decode on a multiplexed stream.
00591 // Pulls the 0xe0 stream.
00592 void oxp_mpeg_codec::set_demux_video()
00593 {
00594   impl_->demux_track = 0xe0;
00595 }
00596 
00597 void oxp_mpeg_codec::set_output_format_grey()
00598 {
00599   impl_->output_format = oxp_mpeg_codec_data::grey;
00600 }
00601 
00602 void oxp_mpeg_codec::set_output_format_rgb()
00603 {
00604   impl_->output_format = oxp_mpeg_codec_data::rgb;
00605 }
00606 
00607 #if 0
00608 void my_decoder::dummy_chunk()
00609 {
00610   // I don't now what 0xB1 is for but libmpeg2 ignores it.
00611   static unsigned char const dummy[] = { 0, 0, 1, 0xB1 };
00612   decode(dummy, dummy + sizeof dummy);
00613 }
00614 #endif
00615 
00616 /////////////////////////////////////////////////////////////////////////////
00617 
00618 #define DEMUX_PAYLOAD_START 1
00619 static int demux(oxp_mpeg_codec_data* impl, unsigned char const *buf, unsigned char const *end, int flags)
00620 {
00621   static int mpeg1_skip_table[16] = { 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
00622 
00623   // the demuxer keeps some state between calls:
00624   // if "state" = DEMUX_HEADER, then "head_buf" contains the first
00625   //     "bytes" bytes from some header.
00626   // if "state" == DEMUX_DATA, then we need to copy "bytes" bytes
00627   //     of ES data before the next header.
00628   // if "state" == DEMUX_SKIP, then we need to skip "bytes" bytes
00629   //     of data before the next header.
00630   //
00631   // NEEDBYTES makes sure we have the requested number of bytes for a
00632   // header. If we don't, it copies what we have into head_buf and returns,
00633   // so that when we come back with more data we finish decoding this header.
00634   //
00635   // DONEBYTES updates "buf" to point after the header we just parsed.
00636 
00637 #define DEMUX_HEADER 0
00638 #define DEMUX_DATA 1
00639 #define DEMUX_SKIP 2
00640   static int state = DEMUX_SKIP;
00641   static int state_bytes = 0;
00642   static uint8_t head_buf[264];
00643 
00644   uint8_t * header;
00645   int bytes;
00646   int len;
00647 
00648 #define NEEDBYTES(x)                                  \
00649   do {                                                \
00650     int missing = (x) - bytes;                        \
00651     if (missing > 0) {                                \
00652       if (header == head_buf) {                       \
00653         if (missing <= end - buf) {                   \
00654           vcl_memcpy(header + bytes, buf, missing);   \
00655           buf += missing;                             \
00656           bytes = (x);                                \
00657         }                                             \
00658         else {                                        \
00659           vcl_memcpy(header + bytes, buf, end - buf); \
00660           state_bytes = bytes + end - buf;            \
00661           return 0;                                   \
00662         }                                             \
00663       }                                               \
00664       else {                                          \
00665         vcl_memcpy(head_buf, header, bytes);          \
00666         state = DEMUX_HEADER;                         \
00667         state_bytes = bytes;                          \
00668         return 0;                                     \
00669       }                                               \
00670     }                                                 \
00671   } while (false)
00672 
00673 #define DONEBYTES(x)        \
00674   do {                      \
00675     if (header != head_buf) \
00676       buf = header + (x);   \
00677   } while (false)
00678 
00679   // demux routine starts here.  above is var and fn defns.
00680   if (flags & DEMUX_PAYLOAD_START)
00681     goto payload_start;
00682   switch (state) {
00683   case DEMUX_HEADER:
00684     if (state_bytes > 0)
00685     {
00686       header = head_buf;
00687       bytes = state_bytes;
00688       goto continue_header;
00689     }
00690     break;
00691   case DEMUX_DATA:
00692     if (impl->demux_pid || (state_bytes > end - buf))
00693     {
00694       impl->decode_mpeg2(buf, end);
00695       state_bytes -= end - buf;
00696       return 0;
00697     }
00698     impl->decode_mpeg2(buf, buf + state_bytes);
00699     buf += state_bytes;
00700     break;
00701   case DEMUX_SKIP:
00702     if (impl->demux_pid || (state_bytes > end - buf))
00703     {
00704       state_bytes -= end - buf;
00705       return 0;
00706     }
00707     buf += state_bytes;
00708     break;
00709   }
00710 
00711   while (true) {
00712     if (impl->demux_pid)
00713     {
00714       state = DEMUX_SKIP;
00715       return 0;
00716     }
00717   payload_start:
00718     header = const_cast<unsigned char*>(buf); // bletcherous const_cast -- it will write into the user's space.
00719     bytes = end - buf;
00720   continue_header:
00721     NEEDBYTES(4);
00722     if (header[0] || header[1] || (header[2] != 1))
00723     {
00724       if (impl->demux_pid)
00725       {
00726         state = DEMUX_SKIP;
00727         return 0;
00728       }
00729       else if (header != head_buf)
00730       {
00731         buf++;
00732         goto payload_start;
00733       }
00734       else
00735       {
00736         header[0] = header[1];
00737         header[1] = header[2];
00738         header[2] = header[3];
00739         bytes = 3;
00740         goto continue_header;
00741       }
00742     }
00743     if (impl->demux_pid)
00744     {
00745       if ((header[3] >= 0xe0) && (header[3] <= 0xef))
00746         goto pes;
00747       vcl_cerr << "bad stream id " << header[3] << '\n';
00748       vcl_exit(1);
00749     }
00750     switch (header[3]) {
00751     case 0xb9: // program end code
00752       // DONEBYTES(4);
00753       // break;
00754       return 1;
00755     case 0xba: // pack header
00756       NEEDBYTES(12);
00757       if ((header[4] & 0xc0) == 0x40) // mpeg2
00758       {
00759         NEEDBYTES(14);
00760         len = 14 + (header[13] & 7);
00761         NEEDBYTES(len);
00762         DONEBYTES(len);
00763         // header points to the mpeg2 pack header
00764       }
00765       else if ((header[4] & 0xf0) == 0x20) // mpeg1
00766       {
00767         DONEBYTES(12);
00768         // header points to the mpeg1 pack header
00769       }
00770       else
00771       {
00772         vcl_cerr << "weird pack header\n";
00773         vcl_exit(1);
00774       }
00775       break;
00776     default:
00777       if (header[3] == impl->demux_track)
00778       {
00779       pes:
00780         NEEDBYTES(7);
00781         if ((header[6] & 0xc0) == 0x80) // mpeg2
00782         {
00783           NEEDBYTES(9);
00784           len = 9 + header[8];
00785           NEEDBYTES(len);
00786           // header points to the mpeg2 pes header
00787         }
00788         else // mpeg1
00789         {
00790           len = 7;
00791           while ((header-1)[len] == 0xff) {
00792             len++;
00793             NEEDBYTES(len);
00794             if (len == 23)
00795             {
00796               vcl_cerr << "too much stuffing\n";
00797               break;
00798             }
00799           }
00800           if (((header-1)[len] & 0xc0) == 0x40)
00801           {
00802             len += 2;
00803             NEEDBYTES(len);
00804           }
00805           len += mpeg1_skip_table[(header - 1)[len] >> 4];
00806           NEEDBYTES(len);
00807           // header points to the mpeg1 pes header
00808         }
00809         DONEBYTES(len);
00810         bytes = 6 + (header[4] << 8) + header[5] - len;
00811         if (impl->demux_pid || (bytes > end - buf))
00812         {
00813           impl->decode_mpeg2(buf, end);
00814           state = DEMUX_DATA;
00815           state_bytes = bytes - (end - buf);
00816           return 0;
00817         }
00818         else if (bytes <= 0)
00819           continue;
00820         impl->decode_mpeg2(buf, buf + bytes);
00821         buf += bytes;
00822       }
00823       else if (header[3] < 0xb9)
00824       {
00825         vcl_cerr << "looks like a video stream, not system stream\n";
00826         vcl_exit(1);
00827       }
00828       else
00829       {
00830         NEEDBYTES(6);
00831         DONEBYTES(6);
00832         bytes = (header[4] << 8) + header[5];
00833         if (bytes > end - buf)
00834         {
00835           state = DEMUX_SKIP;
00836           state_bytes = bytes - (end - buf);
00837           return 0;
00838         }
00839         buf += bytes;
00840       }
00841     }
00842   }
00843 }
00844 
00845 #if 0
00846 static void ts_loop(void)
00847 {
00848 #define PACKETS (BUFFER_SIZE / 188)
00849   int packets;
00850   do {
00851     packets = vcl_fread(buffer, 188, PACKETS, in_file);
00852     for (int i = 0; i < packets; i++)
00853     {
00854       uint8_t * buf = buffer + i * 188;
00855       uint8_t * end = buf + 188;
00856       if (buf[0] != 0x47)
00857       {
00858         vcl_cerr << "bad sync byte\n";
00859         vcl_exit(1);
00860       }
00861       int pid = ((buf[1] << 8) + buf[2]) & 0x1fff;
00862       if (pid != impl->demux_pid)
00863         continue;
00864       uint8_t * data = buf + 4;
00865       if (buf[3] & 0x20) // buf contains an adaptation field
00866       {
00867         data = buf + 5 + buf[4];
00868         if (data > end)
00869           continue;
00870       }
00871       if (buf[3] & 0x10)
00872         demux(data, end, (buf[1] & 0x40) ? DEMUX_PAYLOAD_START : 0);
00873     }
00874   } while (packets == PACKETS);
00875 }
00876 #endif
00877 
00878 int oxp_mpeg_codec::get_width() const
00879 {
00880   return impl_->w;
00881 }
00882 
00883 int oxp_mpeg_codec::get_height() const
00884 {
00885   return impl_->h;
00886 }

Generated on Thu Jan 10 14:46:06 2008 for contrib/oxl/oxp by  doxygen 1.4.4