Panda3D
|
00001 // Filename: ffmpegVirtualFile.cxx 00002 // Created by: jyelon (02Jul07) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #ifdef HAVE_FFMPEG 00016 00017 #include "pandabase.h" 00018 #include "config_movies.h" 00019 #include "ffmpegVirtualFile.h" 00020 #include "virtualFileSystem.h" 00021 extern "C" { 00022 #include "libavformat/avio.h" 00023 } 00024 00025 #ifndef AVSEEK_SIZE 00026 #define AVSEEK_SIZE 0x10000 00027 #endif 00028 00029 //////////////////////////////////////////////////////////////////// 00030 // These functions need to use C calling conventions. 00031 //////////////////////////////////////////////////////////////////// 00032 extern "C" { 00033 static int pandavfs_open(URLContext *h, const char *filename, int flags); 00034 static int pandavfs_read(URLContext *h, unsigned char *buf, int size); 00035 // This change happened a few days before 52.68.0 00036 #if LIBAVFORMAT_VERSION_INT < 3425280 00037 static int pandavfs_write(URLContext *h, unsigned char *buf, int size); 00038 #else 00039 static int pandavfs_write(URLContext *h, const unsigned char *buf, int size); 00040 #endif 00041 static int64_t pandavfs_seek(URLContext *h, int64_t pos, int whence); 00042 static int pandavfs_close(URLContext *h); 00043 } 00044 00045 //////////////////////////////////////////////////////////////////// 00046 // Function: pandavfs_open 00047 // Access: Static Function 00048 // Description: A hook to open a panda VFS file. 00049 //////////////////////////////////////////////////////////////////// 00050 static int 00051 pandavfs_open(URLContext *h, const char *filename, int flags) { 00052 if (flags != 0) { 00053 movies_cat.error() << "ffmpeg is trying to write to the VFS.\n"; 00054 return -1; 00055 } 00056 filename += 9; // Skip over "pandavfs:" 00057 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00058 istream *s = vfs->open_read_file(filename, true); 00059 if (s == 0) { 00060 return -1; 00061 } 00062 // Test whether seek works. 00063 s->seekg(1, ios::beg); 00064 int tel1 = s->tellg(); 00065 s->seekg(0, ios::beg); 00066 int tel2 = s->tellg(); 00067 if (s->fail() || (tel1!=1) || (tel2!=0)) { 00068 movies_cat.error() << "cannot play movie (not seekable): " << h->filename << "\n"; 00069 delete s; 00070 return -1; 00071 } 00072 h->priv_data = s; 00073 return 0; 00074 } 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: pandavfs_read 00078 // Access: Static Function 00079 // Description: A hook to read a panda VFS file. 00080 //////////////////////////////////////////////////////////////////// 00081 static int 00082 pandavfs_read(URLContext *h, unsigned char *buf, int size) { 00083 istream *s = (istream*)(h->priv_data); 00084 s->read((char*)buf, size); 00085 int gc = s->gcount(); 00086 s->clear(); 00087 return gc; 00088 } 00089 00090 //////////////////////////////////////////////////////////////////// 00091 // Function: pandavfs_write 00092 // Access: Static Function 00093 // Description: A hook to write a panda VFS file. 00094 //////////////////////////////////////////////////////////////////// 00095 static int 00096 #if LIBAVFORMAT_VERSION_INT < 3425280 00097 pandavfs_write(URLContext *h, unsigned char *buf, int size) { 00098 #else 00099 pandavfs_write(URLContext *h, const unsigned char *buf, int size) { 00100 #endif 00101 movies_cat.error() << "ffmpeg is trying to write to the VFS.\n"; 00102 return -1; 00103 } 00104 00105 //////////////////////////////////////////////////////////////////// 00106 // Function: pandavfs_seek 00107 // Access: Static Function 00108 // Description: A hook to seek a panda VFS file. 00109 //////////////////////////////////////////////////////////////////// 00110 static PN_int64 00111 pandavfs_seek(URLContext *h, PN_int64 pos, int whence) { 00112 istream *s = (istream*)(h->priv_data); 00113 switch(whence) { 00114 case SEEK_SET: s->seekg(pos, ios::beg); break; 00115 case SEEK_CUR: s->seekg(pos, ios::cur); break; 00116 case SEEK_END: s->seekg(pos, ios::end); break; 00117 case AVSEEK_SIZE: { 00118 s->seekg(0, ios::cur); 00119 int p = s->tellg(); 00120 s->seekg(-1, ios::end); 00121 int size = s->tellg(); 00122 if (size < 0) { 00123 movies_cat.error() << "Failed to determine filesize in ffmpegVirtualFile\n"; 00124 s->clear(); 00125 return -1; 00126 } 00127 size++; 00128 s->seekg(p, ios::beg); 00129 s->clear(); 00130 return size; } 00131 default: 00132 movies_cat.error() << "Illegal parameter to seek in ffmpegVirtualFile\n"; 00133 s->clear(); 00134 return -1; 00135 } 00136 s->clear(); 00137 int tl = s->tellg(); 00138 return tl; 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: pandavfs_close 00143 // Access: Static Function 00144 // Description: A hook to close a panda VFS file. 00145 //////////////////////////////////////////////////////////////////// 00146 static int 00147 pandavfs_close(URLContext *h) { 00148 istream *s = (istream*)(h->priv_data); 00149 delete s; 00150 h->priv_data = 0; 00151 return 0; 00152 } 00153 00154 //////////////////////////////////////////////////////////////////// 00155 // Function: FfmpegVirtualFile::register_protocol 00156 // Access: Public, Static 00157 // Description: Enables ffmpeg to access panda's VFS. 00158 // 00159 // After calling this method, ffmpeg will be 00160 // able to open "URLs" that look like this: 00161 // 00162 // pandavfs:/c/mygame/foo.avi 00163 // 00164 //////////////////////////////////////////////////////////////////// 00165 void FfmpegVirtualFile:: 00166 register_protocol() { 00167 static bool initialized = false; 00168 if (initialized) { 00169 return; 00170 } 00171 static URLProtocol protocol; 00172 protocol.name = "pandavfs"; 00173 protocol.url_open = pandavfs_open; 00174 protocol.url_read = pandavfs_read; 00175 protocol.url_write = pandavfs_write; 00176 protocol.url_seek = pandavfs_seek; 00177 protocol.url_close = pandavfs_close; 00178 #if LIBAVFORMAT_VERSION_INT < 3415296 00179 ::register_protocol(&protocol); 00180 #else 00181 av_register_protocol(&protocol); 00182 #endif 00183 } 00184 00185 #endif // HAVE_FFMPEG