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

SGIMovieFile.cxx

Go to the documentation of this file.
00001 // This is oxl/oxp/SGIMovieFile.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 
00006 #include "SGIMovieFile.h"
00007 #include "SGIMovieFilePrivates.h"
00008 
00009 #include <vcl_fstream.h>
00010 #include <vcl_sstream.h>
00011 #include <vcl_cstdio.h>
00012 #include <vcl_cstring.h>
00013 #include <vcl_cstddef.h> // for std::size_t
00014 
00015 #include <oxp/JPEG_Decompressor.h>
00016 #include <vxl_config.h>
00017 #include <vpl/vpl_fileno.h>
00018 
00019 /////////////////////////////////////////////////////////////////////////////
00020 static int get_u16(vcl_istream& f);
00021 static unsigned long get_u32(vcl_istream& f);
00022 
00023 /////////////////////////////////////////////////////////////////////////////
00024 
00025 SGIMovieFile::SGIMovieFile(char const* f)
00026 {
00027   p = new SGIMovieFilePrivates(f);
00028 }
00029 
00030 SGIMovieFile::~SGIMovieFile()
00031 {
00032   delete p;
00033 }
00034 
00035 int SGIMovieFile::GetLength()
00036 {
00037   return p->video_indices[0].size();
00038 }
00039 
00040 vil1_image SGIMovieFile::GetImage(int)
00041 {
00042   return 0;
00043 }
00044 
00045 
00046 int SGIMovieFile::GetSizeX(int)
00047 {
00048   return p->width;
00049 }
00050 
00051 int SGIMovieFile::GetSizeY(int)
00052 {
00053   return p->height;
00054 }
00055 
00056 int SGIMovieFile::GetBitsPixel()
00057 {
00058   return 24; // fixme
00059 }
00060 
00061 bool SGIMovieFile::IsInterlaced()
00062 {
00063   return p->interlaced != 0;
00064 }
00065 
00066 int SGIMovieFile::GetFrameOffset(int frame_index)
00067 {
00068   return p->video_indices[0][frame_index].offset;
00069 }
00070 
00071 int SGIMovieFile::GetFrameSize(int frame_index)
00072 {
00073   return p->video_indices[0][frame_index].size;
00074 }
00075 
00076 bool SGIMovieFile::HasFrame(int frame_index)
00077 {
00078   return 0 <= frame_index && frame_index < GetLength();
00079 }
00080 
00081 SGIMovieFilePrivates::SGIMovieFilePrivates(char const* fn):
00082   filename(fn)
00083 {
00084   // File header is like:
00085   //   V2:
00086   //   byte MOVI[4];
00087   //   short v2; // 2
00088   //   short width;
00089   //   short height;
00090   //   short pad;
00091   //
00092   //   V3:
00093   //   byte MOVI[4];
00094   //   word version;
00095   //   word pad;
00096 
00097   vcl_ifstream f(fn);
00098   char buf[4];
00099   f.read(buf,4);
00100   if (vcl_strncmp(buf,"MOVI",4) != 0) {
00101     vcl_cerr << "SGIMovieFile: Not a movie file, magic = ["
00102              << int(buf[0]) << int(buf[1]) << int(buf[2]) << int(buf[3]) << "]\n";
00103     version = 0;
00104     return;
00105   }
00106 
00107   // Read version
00108   version = get_u16(f);
00109 
00110   if (version == 2) {
00111     // Old format
00112     if (MovieFileInterface::verbose)
00113       vcl_cerr << "SGIMovieFile: Old format, version = " << version << '\n';
00114     width = get_u16(f);
00115     height = get_u16(f);
00116     /* int pad = */ get_u16(f);
00117   } else {
00118     int version1 = get_u16(f);
00119     version = (version << 16) + version1;
00120     if (MovieFileInterface::verbose)
00121       vcl_cerr << "SGIMovieFile: New format, version = " << version << '\n';
00122 
00123     /* int pad = */ get_u32(f);
00124   }
00125 
00126 //   SGIMV_Variables glob;
00127 //   SGIMV_Variables audio[glob.__NUM_A_TRACKS];
00128 //   SGIMV_Variables video[glob.__NUM_I_TRACKS];
00129 //
00130 
00131   glob = new SGIMV_Variables(f);
00132   if (MovieFileInterface::verbose) glob->print(vcl_cerr);
00133 
00134   int NUM_I_TRACKS = glob->get_int("__NUM_I_TRACKS");
00135   int NUM_A_TRACKS = glob->get_int("__NUM_A_TRACKS");
00136   if (MovieFileInterface::verbose)
00137     vcl_cerr << "SGIMovieFile: Number of audio/video tracks: " << NUM_A_TRACKS << '/' << NUM_I_TRACKS << '\n';
00138 
00139   // Load Audio and video info
00140   for (int i = 0; i < NUM_A_TRACKS; ++i)
00141     audio.push_back(SGIMV_Variables(f));
00142 
00143   for (int i = 0; i < NUM_I_TRACKS; ++i)
00144     video.push_back(SGIMV_Variables(f));
00145 
00146   // Assign vars
00147   width = video[0].get_int("WIDTH");
00148   height = video[0].get_int("HEIGHT");
00149   interlaced = video[0].get_int("INTERLACING");
00150   compression = video[0].data["COMPRESSION"];
00151 
00152   if (MovieFileInterface::verbose) {
00153     // Print
00154     for (int i = 0; i < NUM_A_TRACKS; ++i)
00155       audio[i].print(vcl_cerr);
00156 
00157   // Video SGIMV_Variables:
00158   //       COMPRESSION = "1": MVC1, "2": RGB32, "10": JPEG, "MVC2"
00159   //               FPS = 25.000000
00160   //            HEIGHT = 576
00161   //       INTERLACING = 1
00162   //       ORIENTATION = 1100
00163   //           PACKING = 1001
00164   //      PIXEL_ASPECT = 1.000000
00165   //         Q_SPATIAL = 0.750000
00166   //        Q_TEMPORAL = 0.750000
00167   //             WIDTH = 768
00168   //       __DIR_COUNT = 750
00169   //
00170     for (int i = 0; i < NUM_I_TRACKS; ++i)
00171       video[i].print(vcl_cerr);
00172   }
00173 
00174   // Load indices
00175   for (int i = 0; i < NUM_A_TRACKS; ++i)
00176     audio_indices.push_back(SGIMV_FrameIndexArray(f, audio[i].get_int("__DIR_COUNT")));
00177 
00178   for (int i = 0; i < NUM_I_TRACKS; ++i) {
00179     int nframes = video[i].get_int("__DIR_COUNT");
00180     video_indices.push_back(SGIMV_FrameIndexArray(f, nframes));
00181     SGIMV_FrameIndexArray& frame_indices = video_indices[i];
00182     field_indices.push_back(vcl_vector<int>(nframes * 2, 0));
00183     // Fill every second field index.
00184     for (int ff = 0; ff < nframes; ++ff)
00185       field_indices[i][ff*2] = frame_indices[ff].offset;
00186   }
00187 
00188   SGIMV_FrameIndexArray& video_index = video_indices[0];
00189   if (MovieFileInterface::verbose) {
00190     for (unsigned i = 0; i < video_index.size(); ++i) {
00191       if (i > 10 && i < 740)
00192         continue;
00193       vcl_cerr << "SGIMovieFile: Frame " << i;
00194       if (NUM_A_TRACKS > 0)
00195         vcl_cerr << ",  Audio at " << audio_indices[0][i].offset << ", size " << audio_indices[0][i].size;
00196       if (NUM_I_TRACKS > 0)
00197         vcl_cerr << ",  Video at " << video_indices[0][i].offset << ", size " << video_indices[0][i].size;
00198       vcl_cerr << '\n';
00199     }
00200 
00201     vcl_cerr << "SGIMovieFile: Final position, after reading header, is " << (long)f.tellg() << '\n';
00202   }
00203 }
00204 
00205 bool SGIMovieFile::GetFrame(int frame_index, void* buffer)
00206 {
00207   if (p->compression != "2" && p->compression != "10") {
00208     vcl_cerr << "SGIMovieFile: Can't decompress ``" << p->compression << "'' format images\n";
00209     return false;
00210   }
00211 
00212   // int n = p->video_indices[0][frame_index].size;
00213   int s = p->video_indices[0][frame_index].offset;
00214 
00215   // Need to open file every time...
00216   FILE * fp = vcl_fopen(p->filename.c_str(), "r");
00217   if (!fp) {
00218     vcl_cerr << "SGIMovieFile: File has disappeared\n";
00219     return false;
00220   }
00221 
00222   // Seek to image
00223   fseek(fp, s, SEEK_SET);
00224 
00225   int in_bytes_per_pixel = 4;  // RGB32
00226   int bytes_per_pixel = 3;
00227   int interlace_factor = p->interlaced ? 2 : 1;
00228 
00229   if (p->compression == "2")
00230   {
00231     // RGB32 extract to RGB byte-triplet buffer
00232     if (MovieFileInterface::verbose)
00233       vcl_cerr << "[RGB32 " << frame_index << " @ " << s << ' ';
00234 
00235     int w = p->width;
00236     int h = p->height / interlace_factor;
00237     int inrowsize = w * in_bytes_per_pixel;
00238     int outrowsize = w * bytes_per_pixel;
00239     char* row_buf = new char[inrowsize];
00240 
00241     char r,g,b;
00242     for (int i=0; i < interlace_factor; ++i)
00243     {
00244       if (MovieFileInterface::verbose)
00245         vcl_cerr << "fld " << i << ' ';
00246       for (int y=h-1; y >= 0; --y)
00247       {
00248         vcl_fread(row_buf, 1, inrowsize, fp);
00249         char* buf_ptr = (char*)buffer + (interlace_factor * y + i) * outrowsize;
00250         char* row_ptr = row_buf;
00251         for (int x=0; x < w; ++x) {
00252           row_ptr++;   // Skip alpha byte
00253           b = *(row_ptr++);
00254           g = *(row_ptr++);
00255           r = *(row_ptr++);
00256           *(buf_ptr++) = r;  // R
00257           *(buf_ptr++) = g;  // G
00258           *(buf_ptr++) = b;  // B
00259         }
00260       }
00261     }
00262 
00263     if (MovieFileInterface::verbose) vcl_cerr << "] ";
00264     vcl_fclose(fp);
00265     delete[] row_buf;
00266   }
00267   else if (p->compression == "10")
00268   {
00269     // JPEG
00270     if (MovieFileInterface::verbose)
00271       vcl_cerr << "[JPEG " << frame_index << " @ " << s << ' ';
00272 
00273     JPEG_Decompressor jpeg(vpl_fileno(fp));
00274     for (int i = 0; i < interlace_factor; ++i)
00275     {
00276       if (MovieFileInterface::verbose)
00277         vcl_cerr << "fld " << i << ' ';
00278       if (i > 0) jpeg.StartNextJPEG();
00279 
00280       int w = jpeg.width();
00281       int h = jpeg.height();
00282 
00283       if (w != p->width) {
00284         vcl_cerr << "SGIMovieFile: Discrepancy between jpeg size and movie size.  jpeg x = "
00285                  << h << ", movie x = " << p->height << '\n';
00286       }
00287       if (h*interlace_factor != p->height) {
00288         vcl_cerr << "SGIMovieFile: Discrepancy between jpeg size and movie size.  jpeg y = "
00289                  << h << ", movie y = " << p->height << ", interlacing = " << p->interlaced << '\n';
00290       }
00291 
00292       int outrowsize = w * bytes_per_pixel;
00293       for (int y = 0; y < jpeg.height(); ++y) {
00294         char *jbuf = (char*)jpeg.GetNextScanLine();
00295         if (!jbuf) {
00296           vcl_cerr << "SGIMovieFile: JPEG_Decompressor failed to load scanline " << y
00297                    << ", field " << i << ", frame " << frame_index << '\n';
00298           return false;
00299         }
00300         char* bufptr = (char*)buffer + (interlace_factor * y + i) * outrowsize;
00301         vcl_memcpy(bufptr, jbuf, jpeg.width() * bytes_per_pixel);
00302       }
00303       if (MovieFileInterface::verbose)
00304         vcl_cerr << "eof " << jpeg.GetFilePosition() << ' ';
00305 
00306       // Now file position is at second field if interlaced, remember it in case anyone wants this field again.
00307       if (p->interlaced && i == 0)
00308         p->field_indices[0][frame_index * 2 + 1] = jpeg.GetFilePosition();
00309     }
00310     if (MovieFileInterface::verbose) vcl_cerr << "] ";
00311     vcl_fclose(fp);
00312   }
00313 
00314   return true;
00315 }
00316 
00317 bool SGIMovieFile::GetField(int /*field_index*/, void* /*buffer*/)
00318 {
00319   vcl_cerr << "SGIMovieFile::GetField() not yet implemented\n";
00320   return false;
00321 #if 0 // TODO
00322   if (!p->interlaced)
00323     return GetFrame(field_index, buffer);
00324 
00325   // Load a jpeg from fd...
00326   if (p->compression != "10")
00327     vcl_cerr << "SGIMovieFile: Can't decompress ``" << p->compression << "'' format images\n";
00328   else
00329   {
00330     int field_start = p->field_indices[0][field_index];
00331     JPEG_Decompressor *jpeg;
00332     if (field_start == 0)
00333     {
00334       int frame_index = field_index / 2;
00335       int frame_start = p->video_indices[0][frame_index].offset;
00336       // Must go to the start of the frame and read forward
00337       p->fp->seekg(frame_start);
00338 
00339       jpeg = new JPEG_Decompressor(p->fp->rdbuf()->fd());
00340       for (int y = 0; y < jpeg->height(); ++y)
00341         jpeg->GetNextScanLine();
00342 
00343       // Now file position is at second field, remember it in case anyone wants this field again.
00344       p->field_indices[0][frame_index * 2 + 1] = jpeg->GetFilePosition();
00345 
00346       jpeg->StartNextJPEG();
00347     }
00348     else {
00349       p->fp->seekg(field_start);
00350       jpeg = new JPEG_Decompressor(p->fp->rdbuf()->fd());
00351     }
00352 
00353     // Read the image
00354     int w = jpeg->width();
00355     int h = jpeg->height();
00356 
00357     if (w != p->width) {
00358       vcl_cerr << "SGIMovieFile: Discrepancy between jpeg size and movie size.  jpeg x = "
00359                << h << ", movie x = " << p->height << '\n';
00360     }
00361     if (h*2 != p->height) {
00362       vcl_cerr << "SGIMovieFile: Discrepancy between jpeg size and movie size.  jpeg y = "
00363                << h << ", movie y = " << p->height << ", interlacing = " << p->interlaced << '\n';
00364     }
00365 
00366     int bytes_per_pixel = GetBitsPixel() / 8;
00367     int outrowsize = w * bytes_per_pixel;
00368     for (int y = 0; y < jpeg->height(); ++y) {
00369       char *jbuf = (char*)jpeg->GetNextScanLine();
00370       if (!jbuf) {
00371         vcl_cerr << "SGIMovieFile: JPEG_Decompressor failed to load scanline " << y << ", field " << field_index << '\n';
00372         return false;
00373       }
00374       char* bufptr = (char*)buffer + y * outrowsize;
00375       vcl_memcpy(bufptr, jbuf, jpeg->width() * bytes_per_pixel);
00376     }
00377 
00378     delete jpeg;
00379   }
00380   return true;
00381 #endif
00382 }
00383 
00384 /////////////////////////////////////////////////////////////////////////////
00385 
00386 void SGIMV_Variables::read(vcl_istream& f)
00387 {
00388 #if 0
00389   struct SGIMV_Variables {
00390     word pad;
00391     word num_vars;
00392     word pad;
00393     struct VarData {
00394     byte var_buf[16];
00395     word var_size;
00396     byte var_data[var_size];  // Asciiish variable value
00397     };
00398     VarData data[num_vars];
00399   };
00400 #endif // 0
00401   get_u32(f);
00402   unsigned long n = get_u32(f);
00403   get_u32(f);
00404   if (n > 1000L)
00405     vcl_cerr << "SGIMovieFile: warning: A Variable list is " << n << " elements long\n";
00406   for (unsigned long i = 0; i < n; ++i)
00407   {
00408     char var_buf[17];
00409     f.read(var_buf, 16);
00410     var_buf[16] = 0;
00411 
00412     vcl_size_t var_size = get_u32(f);
00413     vcl_vector<char> val_buf(var_size+1,'\0');
00414     f.read(&val_buf[0], var_size);
00415 
00416     data[vcl_string(var_buf)] = vcl_string(&val_buf[0]);
00417   }
00418 }
00419 
00420 int SGIMV_Variables::get_int(vcl_string const& s)
00421 {
00422   const vcl_string& v = data[s];
00423   if (v.size() == 0)
00424     return -1;
00425   vcl_stringstream vs(v);
00426   int x; vs >> x;
00427   return x;
00428 }
00429 
00430 double SGIMV_Variables::get_double(vcl_string const& s)
00431 {
00432   const vcl_string& v = data[s];
00433   if (v.size() == 0)
00434     return -1.0;
00435   vcl_stringstream vs(v);
00436   double x; vs >> x;
00437   return x;
00438 }
00439 
00440 vcl_ostream& SGIMV_Variables::print(vcl_ostream& s) const
00441 {
00442   s << "SGIMV_Variables: [" << data.size() << "]\n";
00443   for (VarData::const_iterator i = data.begin(); i != data.end(); ++i)
00444     s << "   " << (*i).first << " = " << (*i).second << '\n';
00445   return s;
00446 }
00447 
00448 /////////////////////////////////////////////////////////////////////////////
00449 
00450 SGIMV_FrameIndexArray::SGIMV_FrameIndexArray(vcl_istream& f, int n):
00451   vcl_vector<SGIMV_FrameIndex>(n, SGIMV_FrameIndex())
00452 {
00453 #if 0
00454   struct Index {
00455     word offset;
00456     word size;
00457     word pad;
00458     word frame; // ????
00459   };
00460 #endif // 0
00461   for (int i = 0; i < n; ++i) {
00462     (*this)[i].offset = get_u32(f);
00463     (*this)[i].size = get_u32(f);
00464     get_u32(f);
00465     get_u32(f);
00466     // vcl_cerr << "FMV: " << (*this)[i].offset << ' ' << (*this)[i].size << '\n';
00467   }
00468 }
00469 
00470 /////////////////////////////////////////////////////////////////////////////
00471 #if 0 // unused
00472 static void hexdump(vcl_ifstream& f, int nframes)
00473 {
00474   for (int j = 0; j < nframes; ++j) {
00475     int pos = f.tellg();
00476     vxl_uint_8 buf[16];
00477     f.read((char*)buf,16);
00478     vcl_cerr << pos << ':';
00479     for (int i = 0; i < 16; ++i) {
00480       if (i % 4 == 0) vcl_cerr << ' ';
00481       vcl_cerr << buf[i];
00482     }
00483     vcl_cerr << '\n';
00484   }
00485 }
00486 #endif
00487 
00488 static int get_u16(vcl_istream& f)
00489 {
00490   vxl_uint_8 buf[2];
00491   f.read((char*)buf, 2);
00492   return (buf[0] << 8) + buf[1];
00493 }
00494 
00495 static unsigned long get_u32(vcl_istream& f)
00496 {
00497   vxl_uint_8 buf[4];
00498   f.read((char*)buf, 4);
00499   return ((unsigned long)buf[0] << 24) |
00500          ((unsigned long)buf[1] << 16) |
00501          ((unsigned long)buf[2] <<  8) |
00502           (unsigned long)buf[3];
00503 }

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