Commit ee72a78658c8a559a7ed0c7f4ee9274b77d27929
- Diff rendering mode:
- inline
- side by side
|   | |||
| 16 | 16 | set(LIBSTREAMANALYZER_SOVERSION 0.7) | |
| 17 | 17 | option(BUILD_UTILS "build luceneindexer, xmlindexer, rdfindexer, ontoprint utilities" ON) | |
| 18 | 18 | option(BUILD_DEEPTOOLS "build deep find and deepgrep tools" ON) | |
| 19 | option(ENABLE_XINE | ||
| 20 | "enable Xine support. This adds support for a larger number of media formats(highly unstable)." OFF) | ||
| 21 | option(ENABLE_FFMPEG | ||
| 22 | "enable FFMPEG support. This adds support for a larger number of media formats(testing)." ON) | ||
| 19 | 23 | option(ENABLE_EXIV2 | |
| 20 | 24 | "enable exiv2 support. This allows you to index EXIF/IPTC metadata." ON) | |
| 21 | 25 | set(CLUCENE_MIN_VERSION "0.9.21") |
|   | |||
| 1 | # - Try to find FFMPEG | ||
| 2 | # Once done this will define | ||
| 3 | # | ||
| 4 | # FFMPEG_FOUND - system has FFMPEG | ||
| 5 | # FFMPEG_INCLUDE_DIRS - the FFMPEG include directory | ||
| 6 | # FFMPEG_LIBRARIES - Link these to use FFMPEG | ||
| 7 | # FFMPEG_DEFINITIONS - Compiler switches required for using FFMPEG | ||
| 8 | # | ||
| 9 | # Copyright (c) 2008 Andreas Schneider <mail@cynapses.org> | ||
| 10 | # | ||
| 11 | # Redistribution and use is allowed according to the terms of the New | ||
| 12 | # BSD license. | ||
| 13 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. | ||
| 14 | # | ||
| 15 | |||
| 16 | |||
| 17 | if (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIRS) | ||
| 18 | # in cache already | ||
| 19 | set(FFMPEG_FOUND TRUE) | ||
| 20 | else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIRS) | ||
| 21 | # use pkg-config to get the directories and then use these values | ||
| 22 | # in the FIND_PATH() and FIND_LIBRARY() calls | ||
| 23 | if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) | ||
| 24 | include(UsePkgConfig) | ||
| 25 | pkgconfig(libavcodec _AVCODEC_INCLUDEDIR _AVCODEC_LIBDIR _AVCODEC_LDFLAGS _AVCODEC_CFLAGS) | ||
| 26 | pkgconfig(libavformat _AVFORMAT_INCLUDEDIR _AVFORMAT_LIBDIR _AVFORMAT_LDFLAGS _AVFORMAT_CFLAGS) | ||
| 27 | pkgconfig(libavutil _AVUTIL_INCLUDEDIR _AVUTIL_LIBDIR _AVUTIL_LDFLAGS _AVUTIL_CFLAGS) | ||
| 28 | # pkgconfig(libpostproc _POSTPROC_INCLUDEDIR _POSTPROC_LIBDIR _POSTPROC_LDFLAGS _POSTPROC_CFLAGS) | ||
| 29 | pkgconfig(libswscale _SWSCALE_INCLUDEDIR _SWSCALE_LIBDIR _SWSCALE_LDFLAGS _SWSCALE_CFLAGS) | ||
| 30 | else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) | ||
| 31 | message("Doing find_package(PkgConfig)") | ||
| 32 | find_package(PkgConfig) | ||
| 33 | if (PKG_CONFIG_FOUND) | ||
| 34 | pkg_check_modules(_AVCODEC libavcodec) | ||
| 35 | pkg_check_modules(_AVFORMAT libavformat) | ||
| 36 | pkg_check_modules(_AVUTIL libavutil) | ||
| 37 | # pkg_check_modules(_POSTPROC libpostproc) | ||
| 38 | pkg_check_modules(_SWSCALE libswscale) | ||
| 39 | endif (PKG_CONFIG_FOUND) | ||
| 40 | endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) | ||
| 41 | |||
| 42 | find_path(AVCODEC_INCLUDE_DIR | ||
| 43 | NAMES | ||
| 44 | avcodec.h | ||
| 45 | PATHS | ||
| 46 | ${_AVCODEC_INCLUDEDIR} | ||
| 47 | /usr/include | ||
| 48 | /usr/local/include | ||
| 49 | /opt/local/include | ||
| 50 | /sw/include | ||
| 51 | PATH_SUFFIXES | ||
| 52 | libavcodec | ||
| 53 | ffmpeg | ||
| 54 | NO_DEFAULT_PATH | ||
| 55 | ) | ||
| 56 | |||
| 57 | message("AVCODEC_INCLUDE_DIR = ${AVCODEC_INCLUDE_DIR}") | ||
| 58 | |||
| 59 | mark_as_advanced(AVCODEC_INCLUDE_DIR) | ||
| 60 | |||
| 61 | find_path(AVUTIL_INCLUDE_DIR | ||
| 62 | NAMES | ||
| 63 | avutil.h | ||
| 64 | PATHS | ||
| 65 | ${_AVUTIL_INCLUDEDIR} | ||
| 66 | /usr/include | ||
| 67 | /usr/local/include | ||
| 68 | /opt/local/include | ||
| 69 | /sw/include | ||
| 70 | PATH_SUFFIXES | ||
| 71 | libavutil | ||
| 72 | ffmpeg | ||
| 73 | NO_DEFAULT_PATH | ||
| 74 | ) | ||
| 75 | mark_as_advanced(AVUTIL_INCLUDE_DIR) | ||
| 76 | |||
| 77 | find_path(AVFORMAT_INCLUDE_DIR | ||
| 78 | NAMES | ||
| 79 | avformat.h | ||
| 80 | PATHS | ||
| 81 | ${_AVFORMAT_INCLUDEDIR} | ||
| 82 | /usr/include | ||
| 83 | /usr/local/include | ||
| 84 | /opt/local/include | ||
| 85 | /sw/include | ||
| 86 | PATH_SUFFIXES | ||
| 87 | libavformat | ||
| 88 | ffmpeg | ||
| 89 | NO_DEFAULT_PATH | ||
| 90 | ) | ||
| 91 | mark_as_advanced(AVFORMAT_INCLUDE_DIR) | ||
| 92 | |||
| 93 | if (FALSE) | ||
| 94 | find_path(POSTPROC_INCLUDE_DIR | ||
| 95 | NAMES | ||
| 96 | postprocess.h | ||
| 97 | PATHS | ||
| 98 | ${_POSTPROC_INCLUDEDIR} | ||
| 99 | /usr/include/postproc | ||
| 100 | /usr/local/include/postproc | ||
| 101 | /opt/local/include/postproc | ||
| 102 | /sw/include | ||
| 103 | PATH_SUFFIXES | ||
| 104 | libpostproc | ||
| 105 | ffmpeg | ||
| 106 | ) | ||
| 107 | mark_as_advanced(POSTPROC_INCLUDE_DIR) | ||
| 108 | endif(FALSE) | ||
| 109 | |||
| 110 | find_path(SWSCALE_INCLUDE_DIR | ||
| 111 | NAMES | ||
| 112 | swscale.h | ||
| 113 | PATHS | ||
| 114 | ${_SWSCALE_INCLUDEDIR} | ||
| 115 | /usr/include | ||
| 116 | /usr/local/include | ||
| 117 | /opt/local/include | ||
| 118 | /sw/include | ||
| 119 | PATH_SUFFIXES | ||
| 120 | libswscale | ||
| 121 | ffmpeg | ||
| 122 | NO_DEFAULT_PATH | ||
| 123 | ) | ||
| 124 | mark_as_advanced(SWSCALE_INCLUDE_DIR) | ||
| 125 | |||
| 126 | find_library(AVCODEC_LIBRARY | ||
| 127 | NAMES | ||
| 128 | avcodec | ||
| 129 | PATHS | ||
| 130 | ${_FFMPEG_LIBDIR} | ||
| 131 | /usr/lib | ||
| 132 | /usr/local/lib | ||
| 133 | /opt/local/lib | ||
| 134 | /sw/lib | ||
| 135 | NO_DEFAULT_PATH | ||
| 136 | ) | ||
| 137 | mark_as_advanced(AVCODEC_LIBRARY) | ||
| 138 | |||
| 139 | find_library(AVUTIL_LIBRARY | ||
| 140 | NAMES | ||
| 141 | avutil | ||
| 142 | PATHS | ||
| 143 | ${_FFMPEG_LIBDIR} | ||
| 144 | /usr/lib | ||
| 145 | /usr/local/lib | ||
| 146 | /opt/local/lib | ||
| 147 | /sw/lib | ||
| 148 | NO_DEFAULT_PATH | ||
| 149 | ) | ||
| 150 | mark_as_advanced(AVUTIL_LIBRARY) | ||
| 151 | |||
| 152 | find_library(AVFORMAT_LIBRARY | ||
| 153 | NAMES | ||
| 154 | avformat | ||
| 155 | PATHS | ||
| 156 | ${_FFMPEG_LIBDIR} | ||
| 157 | /usr/lib | ||
| 158 | /usr/local/lib | ||
| 159 | /opt/local/lib | ||
| 160 | /sw/lib | ||
| 161 | NO_DEFAULT_PATH | ||
| 162 | ) | ||
| 163 | mark_as_advanced(AVFORMAT_LIBRARY) | ||
| 164 | |||
| 165 | if (FALSE) | ||
| 166 | find_library(POSTPROC_LIBRARY | ||
| 167 | NAMES | ||
| 168 | postproc | ||
| 169 | PATHS | ||
| 170 | ${_FFMPEG_LIBDIR} | ||
| 171 | /usr/lib | ||
| 172 | /usr/local/lib | ||
| 173 | /opt/local/lib | ||
| 174 | /sw/lib | ||
| 175 | NO_DEFAULT_PATH | ||
| 176 | ) | ||
| 177 | mark_as_advanced(POSTPROC_LIBRARY) | ||
| 178 | endif(FALSE) | ||
| 179 | |||
| 180 | find_library(SWSCALE_LIBRARY | ||
| 181 | NAMES | ||
| 182 | swscale | ||
| 183 | PATHS | ||
| 184 | ${_FFMPEG_LIBDIR} | ||
| 185 | /usr/lib | ||
| 186 | /usr/local/lib | ||
| 187 | /opt/local/lib | ||
| 188 | /sw/lib | ||
| 189 | NO_DEFAULT_PATH | ||
| 190 | ) | ||
| 191 | mark_as_advanced(SWSCALE_LIBRARY) | ||
| 192 | |||
| 193 | if (AVCODEC_LIBRARY) | ||
| 194 | set(AVCODEC_FOUND TRUE) | ||
| 195 | endif (AVCODEC_LIBRARY) | ||
| 196 | if (AVUTIL_LIBRARY) | ||
| 197 | set(AVUTIL_FOUND TRUE) | ||
| 198 | endif (AVUTIL_LIBRARY) | ||
| 199 | if (AVFORMAT_LIBRARY) | ||
| 200 | set(AVFORMAT_FOUND TRUE) | ||
| 201 | endif (AVFORMAT_LIBRARY) | ||
| 202 | |||
| 203 | if (POSTPROC_LIBRARY) | ||
| 204 | set(POSTPROC_FOUND TRUE) | ||
| 205 | endif (POSTPROC_LIBRARY) | ||
| 206 | if (SWSCALE_LIBRARY) | ||
| 207 | set(SWSCALE_FOUND TRUE) | ||
| 208 | endif (SWSCALE_LIBRARY) | ||
| 209 | |||
| 210 | set(FFMPEG_INCLUDE_DIRS | ||
| 211 | ${_AVCODEC_INCLUDEDIR} | ||
| 212 | ${AVCODEC_INCLUDE_DIR} | ||
| 213 | ${AVFORMAT_INCLUDE_DIR} | ||
| 214 | ${AVUTIL_INCLUDE_DIR} | ||
| 215 | ${POSTPROC_INCLUDE_DIR} | ||
| 216 | ${SWSCALE_INCLUDE_DIR} | ||
| 217 | ) | ||
| 218 | |||
| 219 | if (AVCODEC_FOUND) | ||
| 220 | set(FFMPEG_LIBRARIES | ||
| 221 | ${FFMPEG_LIBRARIES} | ||
| 222 | ${AVCODEC_LIBRARY} | ||
| 223 | ) | ||
| 224 | endif (AVCODEC_FOUND) | ||
| 225 | if (AVUTIL_FOUND) | ||
| 226 | set(FFMPEG_LIBRARIES | ||
| 227 | ${FFMPEG_LIBRARIES} | ||
| 228 | ${AVUTIL_LIBRARY} | ||
| 229 | ) | ||
| 230 | endif (AVUTIL_FOUND) | ||
| 231 | if (AVFORMAT_FOUND) | ||
| 232 | set(FFMPEG_LIBRARIES | ||
| 233 | ${FFMPEG_LIBRARIES} | ||
| 234 | ${AVFORMAT_LIBRARY} | ||
| 235 | ) | ||
| 236 | endif (AVFORMAT_FOUND) | ||
| 237 | if (POSTPROC_FOUND) | ||
| 238 | set(FFMPEG_LIBRARIES | ||
| 239 | ${FFMPEG_LIBRARIES} | ||
| 240 | ${POSTPROC_LIBRARY} | ||
| 241 | ) | ||
| 242 | endif (POSTPROC_FOUND) | ||
| 243 | if (SWSCALE_FOUND) | ||
| 244 | set(FFMPEG_LIBRARIES | ||
| 245 | ${FFMPEG_LIBRARIES} | ||
| 246 | ${SWSCALE_LIBRARY} | ||
| 247 | ) | ||
| 248 | endif (SWSCALE_FOUND) | ||
| 249 | |||
| 250 | if (FFMPEG_INCLUDE_DIRS AND FFMPEG_LIBRARIES) | ||
| 251 | set(FFMPEG_FOUND TRUE) | ||
| 252 | endif (FFMPEG_INCLUDE_DIRS AND FFMPEG_LIBRARIES) | ||
| 253 | |||
| 254 | if (FFMPEG_FOUND) | ||
| 255 | if (NOT FFMPEG_FIND_QUIETLY) | ||
| 256 | message(STATUS "Found FFMPEG: ${FFMPEG_LIBRARIES}") | ||
| 257 | endif (NOT FFMPEG_FIND_QUIETLY) | ||
| 258 | else (FFMPEG_FOUND) | ||
| 259 | if (FFMPEG_FIND_REQUIRED) | ||
| 260 | message(FATAL_ERROR "Could not find FFMPEG") | ||
| 261 | endif (FFMPEG_FIND_REQUIRED) | ||
| 262 | endif (FFMPEG_FOUND) | ||
| 263 | |||
| 264 | # show the FFMPEG_INCLUDE_DIRS and FFMPEG_LIBRARIES variables only in the advanced view | ||
| 265 | mark_as_advanced(FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARIES) | ||
| 266 | |||
| 267 | endif (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIRS) |
|   | |||
| 1 | # - Try to find the XINE library | ||
| 2 | # Once done this will define | ||
| 3 | # | ||
| 4 | # XINE_FOUND - system has the XINE library | ||
| 5 | # XINE_VERSION - XINE version | ||
| 6 | # XINE_BUGFIX_VERSION - the XINE bugfix version | ||
| 7 | # XINE_INCLUDE_DIR - the XINE include directory | ||
| 8 | # XINE_LIBRARY - The libraries needed to use XINE | ||
| 9 | # XINE_XCB_FOUND - libxine can use XCB for video output | ||
| 10 | |||
| 11 | # Copyright (c) 2008 Helio Chissini de Castro, <helio@kde.org> | ||
| 12 | # Copyright (c) 2006,2007 Laurent Montel, <montel@kde.org> | ||
| 13 | # Copyright (c) 2006, Matthias Kretz, <kretz@kde.org> | ||
| 14 | # | ||
| 15 | # Redistribution and use is allowed according to the terms of the BSD license. | ||
| 16 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. | ||
| 17 | |||
| 18 | if (XINE_INCLUDE_DIR AND XINE_LIBRARY) | ||
| 19 | # Already in cache, be silent | ||
| 20 | set(Xine_FIND_QUIETLY TRUE) | ||
| 21 | endif (XINE_INCLUDE_DIR AND XINE_LIBRARY) | ||
| 22 | |||
| 23 | IF (NOT WIN32) | ||
| 24 | FIND_PACKAGE(PkgConfig) | ||
| 25 | PKG_CHECK_MODULES(PKG_XINE libxine) | ||
| 26 | ENDIF (NOT WIN32) | ||
| 27 | |||
| 28 | FIND_PATH(XINE_INCLUDE_DIR NAMES xine.h | ||
| 29 | PATHS ${PKG_XINE_INCLUDE_DIRS} ) | ||
| 30 | |||
| 31 | FIND_LIBRARY(XINE_LIBRARY NAMES xine | ||
| 32 | PATHS ${PKG_XINE_LIBRARY_DIRS} ) | ||
| 33 | |||
| 34 | if (XINE_INCLUDE_DIR AND XINE_LIBRARY) | ||
| 35 | set(XINE_FOUND TRUE) | ||
| 36 | string(REGEX REPLACE "[0-9].[0-9]." "" XINE_BUGFIX_VERSION ${PKG_XINE_VERSION}) | ||
| 37 | set(XINE_VERSION ${PKG_XINE_VERSION}) | ||
| 38 | endif (XINE_INCLUDE_DIR AND XINE_LIBRARY) | ||
| 39 | |||
| 40 | |||
| 41 | if( XINE_FOUND ) | ||
| 42 | INCLUDE(CheckCSourceCompiles) | ||
| 43 | SET(CMAKE_REQUIRED_INCLUDES ${XINE_INCLUDE_DIR}) | ||
| 44 | SET(CMAKE_REQUIRED_LIBRARIES ${XINE_LIBRARY}) | ||
| 45 | CHECK_C_SOURCE_COMPILES("#include <xine.h>\nint main()\n{\n xine_open_video_driver(xine_new(), \"auto\", XINE_VISUAL_TYPE_XCB, NULL);\n return 0;\n}\n" XINE_XCB_FOUND) | ||
| 46 | endif(XINE_FOUND) | ||
| 47 | |||
| 48 | if (XINE_FOUND) | ||
| 49 | if (NOT Xine_FIND_QUIETLY) | ||
| 50 | message(STATUS "Found XINE: ${XINE_LIBRARY}") | ||
| 51 | endif (NOT Xine_FIND_QUIETLY) | ||
| 52 | endif (XINE_FOUND) | ||
| 53 | |||
| 54 | MARK_AS_ADVANCED(XINE_INCLUDE_DIR XINE_LIBRARY) |
|   | |||
| 93 | 93 | AnalysisResult analysisresult(path, mtime, *manager.indexWriter(), | |
| 94 | 94 | analyzer, ""); | |
| 95 | 95 | if (realfile) { | |
| 96 | FileInputStream file(path.c_str()); | ||
| 97 | return analysisresult.index(&file); | ||
| 96 | InputStream* file = FileInputStream::open(path.c_str()); | ||
| 97 | int r = analysisresult.index(file); | ||
| 98 | delete file; | ||
| 99 | return r; | ||
| 98 | 100 | } else { | |
| 99 | 101 | return analysisresult.index(0); | |
| 100 | 102 | } | |
| … | … | ||
| 119 | 119 | AnalysisResult analysisresult(filepath, s.st_mtime, | |
| 120 | 120 | indexWriter, *analyzer, parentpath); | |
| 121 | 121 | if (S_ISREG(s.st_mode)) { | |
| 122 | FileInputStream file(filepath.c_str()); | ||
| 123 | analysisresult.index(&file); | ||
| 122 | InputStream* file = FileInputStream::open(filepath.c_str()); | ||
| 123 | analysisresult.index(file); | ||
| 124 | delete file; | ||
| 124 | 125 | } else { | |
| 125 | 126 | analysisresult.index(0); | |
| 126 | 127 | } | |
| … | … | ||
| 194 | 194 | AnalysisResult analysisresult(i->first, i->second.st_mtime, | |
| 195 | 195 | *manager.indexWriter(), *analyzer, path); | |
| 196 | 196 | if (S_ISREG(i->second.st_mode)) { | |
| 197 | FileInputStream file(i->first.c_str()); | ||
| 198 | analysisresult.index(&file); | ||
| 197 | InputStream* file = FileInputStream::open(i->first.c_str()); | ||
| 198 | analysisresult.index(file); | ||
| 199 | delete file; | ||
| 199 | 200 | } else { | |
| 200 | 201 | analysisresult.index(0); | |
| 201 | 202 | } |
|   | |||
| 38 | 38 | heightField = reg.registerField( | |
| 39 | 39 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height"); | |
| 40 | 40 | colorDepthField = reg.registerField( | |
| 41 | "http://www.semanticdesktop.org/ontologies/nfo#colorDepth"); | ||
| 41 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorDepth"); | ||
| 42 | 42 | rdftypeField = reg.typeField; | |
| 43 | 43 | ||
| 44 | 44 | addField(typeField); |
|   | |||
| 57 | 57 | NMM_DRAFT "setNumber"), | |
| 58 | 58 | discCountPropertyName( | |
| 59 | 59 | NMM_DRAFT "setCount"), | |
| 60 | |||
| 60 | |||
| 61 | 61 | musicClassName( | |
| 62 | 62 | NMM_DRAFT "MusicPiece"), | |
| 63 | 63 | audioClassName( | |
| … | … | ||
| 279 | 279 | ||
| 280 | 280 | ICONV_CONST char *input = (char *)data; | |
| 281 | 281 | iconv(conv, &input, &len, &result, &reslen); | |
| 282 | |||
| 282 | |||
| 283 | 283 | return string(out,capacity-reslen); | |
| 284 | 284 | } | |
| 285 | 285 | ||
| … | … | ||
| 302 | 302 | trackNumberField = r.registerField(NMM_DRAFT "trackNumber"); | |
| 303 | 303 | durationField = r.registerField(NFO "duration"); | |
| 304 | 304 | typeField = r.typeField; | |
| 305 | |||
| 305 | |||
| 306 | 306 | bitrateField = r.registerField(NFO "averageBitrate"); | |
| 307 | 307 | samplerateField = r.registerField(NFO "sampleRate"); | |
| 308 | 308 | codecField = r.registerField(NFO "codec"); | |
| … | … | ||
| 321 | 321 | int32_t readAsyncSize(const unsigned char* b) { | |
| 322 | 322 | return (((int32_t)b[0])<<21) + (((int32_t)b[1])<<14) | |
| 323 | 323 | + (((int32_t)b[2])<<7) + ((int32_t)b[3]); | |
| 324 | } | ||
| 324 | } | ||
| 325 | 325 | ||
| 326 | 326 | int32_t | |
| 327 | 327 | readSize(const unsigned char* b, bool async) { | |
| … | … | ||
| 352 | 352 | ID3EndAnalyzer::analyze(Strigi::AnalysisResult& indexable, Strigi::InputStream* in) { | |
| 353 | 353 | if(!in) | |
| 354 | 354 | return -1; | |
| 355 | |||
| 355 | |||
| 356 | 356 | bool found_title = false, found_artist = false, | |
| 357 | 357 | found_album = false, found_comment = false, | |
| 358 | 358 | found_year = false, found_track = false, | |
| 359 | 359 | found_genre = false, found_tag = false; | |
| 360 | 360 | string albumUri; | |
| 361 | 361 | char albumArtNum = '\0'; | |
| 362 | |||
| 362 | |||
| 363 | 363 | // read 10 byte header | |
| 364 | 364 | const char* buf; | |
| 365 | 365 | int32_t nread = in->read(buf, 10, 10); | |
| … | … | ||
| 427 | 427 | if (enc == 0 || enc == 3) { | |
| 428 | 428 | value = string(p+11, strnlen(p+11, size-1)); | |
| 429 | 429 | } else { | |
| 430 | value = conv.convert(p+11,size-1); // FIXME: add similar workaround | ||
| 430 | value = conv.convert(p+11,size-1); // FIXME: add similar workaround | ||
| 431 | 431 | } | |
| 432 | 432 | ||
| 433 | 433 | if (!value.empty()) { | |
| … | … | ||
| 517 | 517 | ostringstream outs; | |
| 518 | 518 | outs << dcount; | |
| 519 | 519 | addStatement(indexable, albumUri, discCountPropertyName, outs.str()); | |
| 520 | } | ||
| 520 | } | ||
| 521 | 521 | } | |
| 522 | 522 | } | |
| 523 | 523 | } | |
| … | … | ||
| 530 | 530 | if (((unsigned char)buf[0] == 0xff) && (((unsigned char)buf[1]&0xfe) == 0xfa) | |
| 531 | 531 | && ((bitrateindex = ((unsigned char)buf[2]>>4)) != 0xf) | |
| 532 | 532 | && ((samplerateindex = (((unsigned char)buf[2]>>2)&3)) != 3 )) { // is this MP3? | |
| 533 | |||
| 533 | |||
| 534 | 534 | indexable.addValue(factory->typeField, audioClassName); | |
| 535 | 535 | // FIXME: no support for VBR :( | |
| 536 | 536 | // ideas: compare bitrate from the frame with stream size/duration from ID3 tags | |
| 537 | 537 | // check several consecutive frames to see if bitrate is different | |
| 538 | 538 | // in neither case you can be sure to properly detected VBR :( | |
| 539 | indexable.addValue(factory->bitrateField, bitrate[bitrateindex]); | ||
| 539 | indexable.addValue(factory->bitrateField, bitrate[bitrateindex]); | ||
| 540 | 540 | indexable.addValue(factory->samplerateField, samplerate[samplerateindex]); | |
| 541 | 541 | indexable.addValue(factory->codecField, "MP3"); | |
| 542 | 542 | indexable.addValue(factory->channelsField, ((buf[3]>>6) == 3 ? 1:2 ) ); | |
| 543 | 543 | } | |
| 544 | |||
| 544 | |||
| 545 | 545 | // Parse ID3v1 tag | |
| 546 | 546 | ||
| 547 | 547 | int64_t insize; | |
| … | … | ||
| 552 | 552 | if (nskip == in->skip(nskip)) | |
| 553 | 553 | if (in->read(buf, 128, 128)==128) | |
| 554 | 554 | if (!strncmp("TAG", buf, 3)) { | |
| 555 | |||
| 555 | |||
| 556 | 556 | found_tag = true; | |
| 557 | |||
| 557 | |||
| 558 | 558 | if (!found_title && buf[3]) | |
| 559 | 559 | indexable.addValue(factory->titleField, string(buf+3, strnlen(buf+3, 30))); | |
| 560 | 560 | if (!found_artist && buf[33]) | |
| … | … | ||
| 566 | 566 | if (!found_comment && buf[97]) | |
| 567 | 567 | indexable.addValue(factory->commentField, string(buf+97, strnlen(buf+97, 30))); | |
| 568 | 568 | if (!found_track && !buf[125] && buf[126]) { | |
| 569 | ostringstream out; | ||
| 570 | out << (int)(buf[126]); | ||
| 571 | indexable.addValue(factory->trackNumberField, out.str()); | ||
| 569 | indexable.addValue(factory->trackNumberField, (int)(buf[126])); | ||
| 572 | 570 | } | |
| 573 | 571 | if (!found_genre && (unsigned char)(buf[127]) < 148) | |
| 574 | 572 | indexable.addValue(factory->genreField, genres[(uint8_t)buf[127]]); |
|   | |||
| 33 | 33 | ||
| 34 | 34 | const string | |
| 35 | 35 | videoClassName( | |
| 36 | NMM_DRAFT "Video"); | ||
| 36 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Video"); | ||
| 37 | 37 | ||
| 38 | 38 | void MpegEndAnalyzerFactory::registerFields(FieldRegister& r) { | |
| 39 | 39 | fields["length"] = r.registerField( |
|   | |||
| 66 | 66 | heightField = reg.registerField( | |
| 67 | 67 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height"); | |
| 68 | 68 | colorDepthField = reg.registerField( | |
| 69 | "http://www.semanticdesktop.org/ontologies/nfo#colorDepth"); | ||
| 69 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorDepth"); | ||
| 70 | 70 | colorModeField = reg.registerField( | |
| 71 | 71 | "http://freedesktop.org/standards/xesam/1.0/core#colorSpace"); | |
| 72 | 72 | compressionField = reg.registerField( | |
| … | … | ||
| 337 | 337 | as.addValue(factory->titleField, value); | |
| 338 | 338 | } else if ("Author" == key) { | |
| 339 | 339 | string authorUri = as.newAnonymousUri(); | |
| 340 | |||
| 340 | |||
| 341 | 341 | as.addValue(factory->authorField, authorUri); | |
| 342 | 342 | as.addTriplet(authorUri, typeFieldName, contactClassName); | |
| 343 | 343 | as.addTriplet(authorUri, fullnameFieldName, value); |
|   | |||
| 202 | 202 | // ensure a decent buffer size | |
| 203 | 203 | string name; | |
| 204 | 204 | AnalysisResult analysisresult(filepath, s.st_mtime, *p->writer, *this); | |
| 205 | FileInputStream file(filepath.c_str()); | ||
| 206 | if (file.status() == Ok) { | ||
| 207 | return analysisresult.index(&file); | ||
| 205 | InputStream* file = FileInputStream::open(filepath.c_str()); | ||
| 206 | signed char r; | ||
| 207 | if (file->status() == Ok) { | ||
| 208 | r = analysisresult.index(file); | ||
| 208 | 209 | } else { | |
| 209 | return analysisresult.index(0); | ||
| 210 | r = analysisresult.index(0); | ||
| 210 | 211 | } | |
| 212 | delete file; | ||
| 213 | return r; | ||
| 211 | 214 | } | |
| 212 | 215 | void | |
| 213 | 216 | StreamAnalyzerPrivate::addFactory(StreamThroughAnalyzerFactory* f) { | |
| … | … | ||
| 318 | 318 | addFactory(new TarEndAnalyzerFactory()); | |
| 319 | 319 | addFactory(new ArEndAnalyzerFactory()); | |
| 320 | 320 | addFactory(new MailEndAnalyzerFactory()); | |
| 321 | addFactory(new MpegEndAnalyzerFactory()); | ||
| 321 | // addFactory(new MpegEndAnalyzerFactory()); //Xine fallback works so much better now | ||
| 322 | 322 | addFactory(new OdfEndAnalyzerFactory()); | |
| 323 | 323 | addFactory(new ZipEndAnalyzerFactory()); | |
| 324 | 324 | addFactory(new ZipExeEndAnalyzerFactory()); |
|   | |||
| 27 | 27 | ADD_STRIGIEA(jpeg jpegendanalyzer.cpp) | |
| 28 | 28 | target_link_libraries(jpeg ${EXIV2_LIBRARIES}) | |
| 29 | 29 | endif(EXIV2_FOUND) | |
| 30 | |||
| 31 | if(XINE_FOUND) | ||
| 32 | include_directories(${XINE_INCLUDE_DIR}) | ||
| 33 | ADD_STRIGIEA(xine xineendanalyzer.cpp) | ||
| 34 | target_link_libraries(xine ${XINE_LIBRARY}) | ||
| 35 | endif(XINE_FOUND) | ||
| 36 | |||
| 37 | if(FFMPEG_FOUND) | ||
| 38 | include_directories(${FFMPEG_INCLUDE_DIRS}) | ||
| 39 | ADD_STRIGIEA(ffmpeg ffmpegendanalyzer.cpp) | ||
| 40 | #set_target_properties( ffmpeg PROPERTIES COMPILE_FLAGS "${FFMPEG_DEFINITIONS}" ) | ||
| 41 | target_link_libraries(ffmpeg ${FFMPEG_LIBRARIES}) | ||
| 42 | endif(FFMPEG_FOUND) |
|   | |||
| 1 | /* This file is part of Strigi Desktop Search | ||
| 2 | * | ||
| 3 | * Copyright (C) 2010 Evgeny Egorochkin <phreedom.stdin@gmail.com> | ||
| 4 | * | ||
| 5 | * This library is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Library General Public | ||
| 7 | * License as published by the Free Software Foundation; either | ||
| 8 | * version 2 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This library is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * Library General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Library General Public License | ||
| 16 | * along with this library; see the file COPYING.LIB. If not, write to | ||
| 17 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 18 | * Boston, MA 02110-1301, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define STRIGI_IMPORT_API | ||
| 22 | #include <strigi/analyzerplugin.h> | ||
| 23 | #include <strigi/streamendanalyzer.h> | ||
| 24 | #include <strigi/analysisresult.h> | ||
| 25 | #include <strigi/fieldtypes.h> | ||
| 26 | #include <strigi/textutils.h> | ||
| 27 | #include <strigi/rdfnamespaces.h> | ||
| 28 | extern "C" { | ||
| 29 | #include <libavcodec/avcodec.h> | ||
| 30 | #include <libavformat/avformat.h> | ||
| 31 | #include <libswscale/swscale.h> | ||
| 32 | } | ||
| 33 | #include <cstring> | ||
| 34 | #include <iostream> | ||
| 35 | #include <sstream> | ||
| 36 | using namespace Strigi; | ||
| 37 | using namespace std; | ||
| 38 | |||
| 39 | class FFMPEGEndAnalyzerFactory; | ||
| 40 | |||
| 41 | class STRIGI_PLUGIN_API FFMPEGEndAnalyzer : public StreamEndAnalyzer { | ||
| 42 | private: | ||
| 43 | const FFMPEGEndAnalyzerFactory* factory; | ||
| 44 | public: | ||
| 45 | FFMPEGEndAnalyzer(const FFMPEGEndAnalyzerFactory* f) :factory(f) {} | ||
| 46 | |||
| 47 | ~FFMPEGEndAnalyzer() {} | ||
| 48 | |||
| 49 | const char* name() const { | ||
| 50 | return "FFMPEGEndAnalyzer"; | ||
| 51 | } | ||
| 52 | bool checkHeader(const char* header, int32_t headersize) const; | ||
| 53 | signed char analyze(AnalysisResult& idx, ::InputStream* in); | ||
| 54 | }; | ||
| 55 | |||
| 56 | class STRIGI_PLUGIN_API FFMPEGEndAnalyzerFactory : public StreamEndAnalyzerFactory { | ||
| 57 | friend class FFMPEGEndAnalyzer; | ||
| 58 | private: | ||
| 59 | StreamEndAnalyzer* newInstance() const { | ||
| 60 | av_register_all(); | ||
| 61 | return new FFMPEGEndAnalyzer(this); | ||
| 62 | } | ||
| 63 | const char* name() const { | ||
| 64 | return "FFMPEGEndAnalyzer"; | ||
| 65 | } | ||
| 66 | void registerFields(FieldRegister& ); | ||
| 67 | |||
| 68 | const RegisteredField* durationProperty; | ||
| 69 | const RegisteredField* widthProperty; | ||
| 70 | const RegisteredField* heightProperty; | ||
| 71 | const RegisteredField* frameRateProperty; | ||
| 72 | const RegisteredField* codecProperty; | ||
| 73 | const RegisteredField* bitrateProperty; | ||
| 74 | const RegisteredField* channelsProperty; | ||
| 75 | const RegisteredField* samplerateProperty; | ||
| 76 | const RegisteredField* titleProperty; | ||
| 77 | const RegisteredField* creatorProperty; | ||
| 78 | const RegisteredField* copyrightProperty; | ||
| 79 | const RegisteredField* commentProperty; | ||
| 80 | const RegisteredField* albumProperty; | ||
| 81 | const RegisteredField* genreProperty; | ||
| 82 | const RegisteredField* trackProperty; | ||
| 83 | const RegisteredField* createdProperty; | ||
| 84 | const RegisteredField* typeProperty; | ||
| 85 | const RegisteredField* hasPartProperty; | ||
| 86 | }; | ||
| 87 | |||
| 88 | const string | ||
| 89 | videoClassName = | ||
| 90 | NFO "Video", | ||
| 91 | audioClassName = | ||
| 92 | NFO "Audio", | ||
| 93 | musicPieceClassName = | ||
| 94 | NMM_DRAFT "MusicPiece", | ||
| 95 | albumClassName = | ||
| 96 | NMM_DRAFT "MusicAlbum", | ||
| 97 | embeddedClassName = | ||
| 98 | NFO "EmbeddedFileDataObject", | ||
| 99 | contactClassName = | ||
| 100 | NCO "Contact", | ||
| 101 | |||
| 102 | typePropertyName = | ||
| 103 | RDF "type", | ||
| 104 | hasPartPropertyName = | ||
| 105 | NIE "hasPart", | ||
| 106 | partOfPropertyName = | ||
| 107 | NIE "isPartOf", | ||
| 108 | |||
| 109 | titlePropertyName = | ||
| 110 | NIE "title", | ||
| 111 | fullnamePropertyName = | ||
| 112 | NCO "fullname", | ||
| 113 | commentPropertyName = | ||
| 114 | NIE "comment", | ||
| 115 | languagePropertyName = | ||
| 116 | NIE "language", | ||
| 117 | genrePropertyName = | ||
| 118 | NMM_DRAFT "genre", | ||
| 119 | trackPropertyName = | ||
| 120 | NMM_DRAFT "trackNumber", | ||
| 121 | createdPropertyName = | ||
| 122 | NIE "contentCreated", | ||
| 123 | creatorPropertyName = | ||
| 124 | NCO "creator", | ||
| 125 | copyrightPropertyName = | ||
| 126 | NIE "copyright", | ||
| 127 | albumPropertyName = | ||
| 128 | NMM_DRAFT "MusicAlbum", | ||
| 129 | |||
| 130 | sampleratePropertyName = | ||
| 131 | NFO "sampleRate", | ||
| 132 | codecPropertyName = | ||
| 133 | NFO "codec", | ||
| 134 | channelsPropertyName = | ||
| 135 | NFO "channels", | ||
| 136 | bitratePropertyName = | ||
| 137 | NFO "averageBitrate", | ||
| 138 | durationPropertyName = | ||
| 139 | NFO "duration", | ||
| 140 | widthPropertyName = | ||
| 141 | NFO "width", | ||
| 142 | heightPropertyName = | ||
| 143 | NFO "height", | ||
| 144 | aspectRatioPropertyName = | ||
| 145 | NFO "aspectRatio", | ||
| 146 | frameRatePropertyName = | ||
| 147 | NFO "frameRate"; | ||
| 148 | |||
| 149 | void | ||
| 150 | FFMPEGEndAnalyzerFactory::registerFields(FieldRegister& r) { | ||
| 151 | durationProperty = r.registerField(durationPropertyName); | ||
| 152 | widthProperty = r.registerField(widthPropertyName); | ||
| 153 | heightProperty = r.registerField(heightPropertyName); | ||
| 154 | frameRateProperty = r.registerField(frameRatePropertyName); | ||
| 155 | codecProperty = r.registerField(codecPropertyName); | ||
| 156 | bitrateProperty = r.registerField(bitratePropertyName); | ||
| 157 | typeProperty = r.typeField; | ||
| 158 | channelsProperty = r.registerField(channelsPropertyName); | ||
| 159 | samplerateProperty = r.registerField(sampleratePropertyName); | ||
| 160 | titleProperty = r.registerField(titlePropertyName); | ||
| 161 | creatorProperty = r.registerField(creatorPropertyName); | ||
| 162 | copyrightProperty = r.registerField(copyrightPropertyName); | ||
| 163 | commentProperty = r.registerField(commentPropertyName); | ||
| 164 | albumProperty = r.registerField(albumPropertyName); | ||
| 165 | genreProperty = r.registerField(genrePropertyName); | ||
| 166 | trackProperty = r.registerField(trackPropertyName); | ||
| 167 | createdProperty = r.registerField(createdPropertyName); | ||
| 168 | hasPartProperty = r.registerField(hasPartPropertyName); | ||
| 169 | } | ||
| 170 | |||
| 171 | // Probe all input formats and obtain score. | ||
| 172 | // Evil FFMPEG hid av_probe_input_format2, the function that does just this. | ||
| 173 | AVInputFormat *probe_format(AVProbeData *pd, int *max_score) { | ||
| 174 | AVInputFormat *result = NULL; | ||
| 175 | *max_score = 0; | ||
| 176 | |||
| 177 | for (AVInputFormat *fmt = av_iformat_next(NULL); fmt != NULL; fmt = av_iformat_next(fmt)) | ||
| 178 | // test only formats that are file-based and can detect the byte stream | ||
| 179 | if (!(fmt->flags & AVFMT_NOFILE) && fmt->read_probe) { | ||
| 180 | int score = fmt->read_probe(pd); | ||
| 181 | if (score > *max_score) { | ||
| 182 | *max_score = score; | ||
| 183 | result = fmt; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | return result; | ||
| 188 | } | ||
| 189 | |||
| 190 | // Input format is probed twice, but compared to the expense of stream metadata extraction this isn't a huge deal. | ||
| 191 | // Unfortunately you can't save probe results in checkHeader because it's const | ||
| 192 | bool | ||
| 193 | FFMPEGEndAnalyzer::checkHeader(const char* header, int32_t headersize) const { | ||
| 194 | AVProbeData pd; | ||
| 195 | pd.buf = (unsigned char*)header; | ||
| 196 | pd.buf_size = headersize; | ||
| 197 | pd.filename =""; | ||
| 198 | int max_score; | ||
| 199 | |||
| 200 | probe_format(&pd, &max_score); | ||
| 201 | |||
| 202 | cout<<"Detection score:"<<max_score<<endl<<flush; | ||
| 203 | // Most of formats return either 100 or nothing | ||
| 204 | // MPG, however, can go as low as 25 while still being a real video | ||
| 205 | return max_score >=25; | ||
| 206 | } | ||
| 207 | |||
| 208 | /*FIXME | ||
| 209 | make it produce the same data in stream and file mode when possible. | ||
| 210 | stream duration,size and bitrate reporting seem to be mostly nonexistent in ffmpeg | ||
| 211 | handle subtitles | ||
| 212 | */ | ||
| 213 | |||
| 214 | extern "C" { | ||
| 215 | int read_data(void *opaque, uint8_t *buf, int buf_size) { | ||
| 216 | cout<<"READ"; | ||
| 217 | InputStream *s = (InputStream *) opaque; | ||
| 218 | if (!s) | ||
| 219 | return -1; | ||
| 220 | |||
| 221 | const char *sbuf; | ||
| 222 | cout<<s->position()<<" "<<flush; | ||
| 223 | int32_t len = s->read(sbuf, buf_size, buf_size); | ||
| 224 | cout<<s->position()<<" "<<buf_size<<" "<<len<<" "<<s->size()<<flush; | ||
| 225 | if (len>0) | ||
| 226 | memcpy( buf, sbuf, len); | ||
| 227 | cout<<" OK\n"<<flush; | ||
| 228 | return len; | ||
| 229 | } | ||
| 230 | |||
| 231 | int64_t seek_data(void *opaque, int64_t offset, int whence) { | ||
| 232 | InputStream *s = (InputStream *) opaque; | ||
| 233 | int64_t target = -1; | ||
| 234 | int64_t size; | ||
| 235 | |||
| 236 | cout<<"SEEK"<<offset<<" "<<whence<<"\n"<<flush; | ||
| 237 | |||
| 238 | if ( whence== SEEK_SET) { | ||
| 239 | target = offset; | ||
| 240 | } else if ( whence == SEEK_CUR ) { | ||
| 241 | target = s->position() + offset; | ||
| 242 | } else if ( (whence == SEEK_END) && (size = s->size()>=0) ) { | ||
| 243 | target = size+offset; | ||
| 244 | } else if ( whence == AVSEEK_SIZE ) { | ||
| 245 | return s->size(); | ||
| 246 | } else | ||
| 247 | return -1; | ||
| 248 | |||
| 249 | int64_t t= s->reset(target); | ||
| 250 | cout<<t<<"\n"<<flush; | ||
| 251 | return (t == target ? target : -1); | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | int64_t const no_bitrate = 0x8000000000000000ULL; | ||
| 256 | |||
| 257 | signed char | ||
| 258 | FFMPEGEndAnalyzer::analyze(AnalysisResult& ar, ::InputStream* in) { | ||
| 259 | uint8_t pDataBuffer[32768];//65536]; | ||
| 260 | long lSize = 32768; | ||
| 261 | |||
| 262 | ByteIOContext ByteIOCtx; | ||
| 263 | if(init_put_byte(&ByteIOCtx, pDataBuffer, lSize, 0, in, read_data, NULL, seek_data) < 0) | ||
| 264 | return -1; | ||
| 265 | |||
| 266 | //pAVInputFormat->flags |= AVFMT_NOFILE; | ||
| 267 | ByteIOCtx.is_streamed = 0; | ||
| 268 | |||
| 269 | AVProbeData pd; | ||
| 270 | const char *buf; | ||
| 271 | pd.filename =""; | ||
| 272 | pd.buf_size = in->read(buf,262144,262144); | ||
| 273 | pd.buf = (unsigned char*)buf; | ||
| 274 | in->reset(0); | ||
| 275 | |||
| 276 | int score; | ||
| 277 | AVInputFormat* fmt = probe_format(&pd, &score); | ||
| 278 | |||
| 279 | AVFormatContext *fc = NULL; | ||
| 280 | if(av_open_input_stream(&fc, &ByteIOCtx, "", fmt, NULL) < 0) | ||
| 281 | return -1; | ||
| 282 | |||
| 283 | av_find_stream_info(fc); | ||
| 284 | |||
| 285 | // Dump information about file onto standard error | ||
| 286 | dump_format(fc, 0, ar.path().c_str(), false); | ||
| 287 | |||
| 288 | if(fc->bit_rate) | ||
| 289 | ar.addValue(factory->bitrateProperty, fc->bit_rate); | ||
| 290 | else if (fc->duration!= no_bitrate) { | ||
| 291 | cout<<"Trying to estimate bitrate\n"; | ||
| 292 | int64_t size; | ||
| 293 | if ((size = in->size()) >= 0) | ||
| 294 | ar.addValue(factory->bitrateProperty, (uint32_t)((size/(fc->duration/AV_TIME_BASE))*8) ); | ||
| 295 | } | ||
| 296 | if(fc->duration!= no_bitrate) | ||
| 297 | ar.addValue(factory->durationProperty, (uint32_t)(fc->duration / AV_TIME_BASE)); | ||
| 298 | else if(fc->bit_rate) { | ||
| 299 | cout<<"Trying to estimate duration\n"; | ||
| 300 | int64_t size; | ||
| 301 | if ((size = in->size()) >= 0) | ||
| 302 | ar.addValue(factory->durationProperty, (uint32_t)(size/(fc->bit_rate/8))); | ||
| 303 | } | ||
| 304 | if(fc->nb_streams==1 && fc->streams[0]->codec->codec_type == CODEC_TYPE_AUDIO) { | ||
| 305 | ar.addValue(factory->typeProperty, NFO "Audio"); | ||
| 306 | ar.addValue(factory->typeProperty, NMM_DRAFT "MusicPiece"); | ||
| 307 | } else { | ||
| 308 | ar.addValue(factory->typeProperty, NFO "Video"); | ||
| 309 | } | ||
| 310 | |||
| 311 | for(uint32_t i=0; i<fc->nb_streams; i++) { | ||
| 312 | const AVStream &stream = *fc->streams[i]; | ||
| 313 | const AVCodecContext &codec = *stream.codec; | ||
| 314 | |||
| 315 | if (codec.codec_type == CODEC_TYPE_AUDIO || codec.codec_type == CODEC_TYPE_VIDEO) { | ||
| 316 | const string streamuri = ar.newAnonymousUri(); | ||
| 317 | ar.addValue(factory->hasPartProperty, streamuri); | ||
| 318 | ar.addTriplet(streamuri, partOfPropertyName, ar.path()); | ||
| 319 | ar.addTriplet(streamuri, typePropertyName, embeddedClassName); | ||
| 320 | |||
| 321 | if ((stream.duration != no_bitrate) && stream.time_base.num && stream.time_base.den) { | ||
| 322 | ostringstream outs; | ||
| 323 | outs << (stream.duration * stream.time_base.num / stream.time_base.den); | ||
| 324 | ar.addTriplet(streamuri, durationPropertyName,outs.str()); | ||
| 325 | } | ||
| 326 | if (size_t len = strlen(stream.language)) { | ||
| 327 | ar.addTriplet(streamuri, languagePropertyName, string(stream.language, len)); | ||
| 328 | } | ||
| 329 | const AVCodec *p = avcodec_find_decoder(codec.codec_id); | ||
| 330 | if (p) { | ||
| 331 | if (size_t len = strlen(p->name)) { | ||
| 332 | ar.addTriplet(streamuri, codecPropertyName, string(p->name, len)); | ||
| 333 | } | ||
| 334 | } else if (size_t len = strlen(codec.codec_name)) { | ||
| 335 | ar.addTriplet(streamuri, codecPropertyName, string(codec.codec_name, len)); | ||
| 336 | } | ||
| 337 | /* | ||
| 338 | 00792 } else if (enc->codec_id == CODEC_ID_MPEG2TS) { | ||
| 339 | // fake mpeg2 transport stream codec (currently not | ||
| 340 | 00794 registered) | ||
| 341 | 00795 codec_name = "mpeg2ts"; | ||
| 342 | 00798 } else { | ||
| 343 | 00799 // output avi tags | ||
| 344 | 00800 if( isprint(enc->codec_tag&0xFF) && isprint((enc->codec_tag>>8)&0xFF) | ||
| 345 | 00801 && isprint((enc->codec_tag>>16)&0xFF) && isprint((enc->codec_tag>>24)&0xFF)){ | ||
| 346 | 00802 snprintf(buf1, sizeof(buf1), "%c%c%c%c / 0x%04X", | ||
| 347 | 00803 enc->codec_tag & 0xff, | ||
| 348 | 00804 (enc->codec_tag >> 8) & 0xff, | ||
| 349 | 00805 (enc->codec_tag >> 16) & 0xff, | ||
| 350 | 00806 (enc->codec_tag >> 24) & 0xff, | ||
| 351 | 00807 enc->codec_tag); | ||
| 352 | 00808 } else { | ||
| 353 | 00809 snprintf(buf1, sizeof(buf1), "0x%04x", enc->codec_tag); | ||
| 354 | 00810 } | ||
| 355 | 00811 codec_name = buf1; | ||
| 356 | 00812 } | ||
| 357 | */ | ||
| 358 | if (codec.bit_rate) { | ||
| 359 | ostringstream outs; | ||
| 360 | outs << codec.bit_rate; | ||
| 361 | ar.addTriplet(streamuri, bitratePropertyName, outs.str()); | ||
| 362 | } | ||
| 363 | |||
| 364 | if (codec.codec_type == CODEC_TYPE_AUDIO) { | ||
| 365 | |||
| 366 | ar.addTriplet(streamuri, typePropertyName, audioClassName); | ||
| 367 | if (codec.channels) { | ||
| 368 | ostringstream outs; | ||
| 369 | outs << codec.channels; | ||
| 370 | ar.addTriplet(streamuri, channelsPropertyName, outs.str()); | ||
| 371 | } | ||
| 372 | if (codec.sample_rate) { | ||
| 373 | ostringstream outs; | ||
| 374 | outs << codec.sample_rate; | ||
| 375 | ar.addTriplet(streamuri, sampleratePropertyName, outs.str()); | ||
| 376 | } | ||
| 377 | if (codec.sample_fmt != SAMPLE_FMT_NONE) {}//FIXME sample format | ||
| 378 | |||
| 379 | } else { // video stream | ||
| 380 | |||
| 381 | ar.addTriplet(streamuri, typePropertyName, videoClassName); | ||
| 382 | if (codec.width) { | ||
| 383 | ostringstream outs; | ||
| 384 | outs << codec.width; | ||
| 385 | ar.addTriplet(streamuri, widthPropertyName, outs.str()); | ||
| 386 | if (codec.sample_aspect_ratio.num) { | ||
| 387 | AVRational aspectratio; | ||
| 388 | ostringstream outs; | ||
| 389 | av_reduce(&aspectratio.num, &aspectratio.den, | ||
| 390 | codec.width * codec.sample_aspect_ratio.num, | ||
| 391 | codec.height * codec.sample_aspect_ratio.den, | ||
| 392 | 1024*1024); | ||
| 393 | outs << aspectratio.num << ":" << aspectratio.den; | ||
| 394 | ar.addTriplet(streamuri, aspectRatioPropertyName, outs.str()); | ||
| 395 | } | ||
| 396 | } | ||
| 397 | if (codec.height) { | ||
| 398 | ostringstream outs; | ||
| 399 | outs << codec.height; | ||
| 400 | ar.addTriplet(streamuri, heightPropertyName, outs.str()); | ||
| 401 | } | ||
| 402 | if (stream.r_frame_rate.num && stream.r_frame_rate.den) { | ||
| 403 | ostringstream outs; | ||
| 404 | outs << stream.r_frame_rate.num / stream.r_frame_rate.den; | ||
| 405 | ar.addTriplet(streamuri, frameRatePropertyName, outs.str()); | ||
| 406 | } | ||
| 407 | if (codec.pix_fmt != PIX_FMT_NONE) {}//FIXME pixel format | ||
| 408 | } | ||
| 409 | |||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | // Tags | ||
| 414 | |||
| 415 | if (int32_t len = strlen(fc->title)) { | ||
| 416 | ar.addValue(factory->titleProperty, string(fc->title, len) ); | ||
| 417 | } | ||
| 418 | if (int32_t len = strlen(fc->author)) { | ||
| 419 | const string creatoruri = ar.newAnonymousUri(); | ||
| 420 | ar.addValue(factory->creatorProperty, creatoruri); | ||
| 421 | ar.addTriplet(creatoruri, typePropertyName, contactClassName); | ||
| 422 | ar.addTriplet(creatoruri, fullnamePropertyName, string(fc->author, len) ); | ||
| 423 | } | ||
| 424 | if (int32_t len = strlen(fc->copyright)) { | ||
| 425 | ar.addValue(factory->copyrightProperty, string(fc->copyright, len) ); | ||
| 426 | } | ||
| 427 | if (int32_t len = strlen(fc->comment)) { | ||
| 428 | ar.addValue(factory->commentProperty, string(fc->comment, len) ); | ||
| 429 | } | ||
| 430 | if (int32_t len = strlen(fc->album)) { | ||
| 431 | const string album = ar.newAnonymousUri(); | ||
| 432 | ar.addValue(factory->albumProperty, album); | ||
| 433 | ar.addTriplet(album, typePropertyName, albumClassName); | ||
| 434 | ar.addTriplet(album, titlePropertyName, string(fc->album, len) ); | ||
| 435 | } | ||
| 436 | if (int32_t len = strlen(fc->genre)) { | ||
| 437 | ar.addValue(factory->genreProperty, string(fc->genre, len) ); | ||
| 438 | } | ||
| 439 | if (fc->track) { | ||
| 440 | ar.addValue(factory->trackProperty, fc->track); | ||
| 441 | } | ||
| 442 | if (fc->year) { | ||
| 443 | ar.addValue(factory->createdProperty, fc->year); | ||
| 444 | } | ||
| 445 | |||
| 446 | av_close_input_stream(fc); | ||
| 447 | //url_fclose(&ByteIOCtx); | ||
| 448 | |||
| 449 | return 0; | ||
| 450 | } | ||
| 451 | |||
| 452 | /* | ||
| 453 | For plugins, we need to have a way to find out which plugins are defined in a | ||
| 454 | plugin. One instance of AnalyzerFactoryFactory per plugin profides this | ||
| 455 | information. | ||
| 456 | */ | ||
| 457 | class Factory : public AnalyzerFactoryFactory { | ||
| 458 | public: | ||
| 459 | list<StreamEndAnalyzerFactory*> | ||
| 460 | streamEndAnalyzerFactories() const { | ||
| 461 | list<StreamEndAnalyzerFactory*> af; | ||
| 462 | af.push_back(new FFMPEGEndAnalyzerFactory()); | ||
| 463 | return af; | ||
| 464 | } | ||
| 465 | }; | ||
| 466 | |||
| 467 | /* | ||
| 468 | Register the AnalyzerFactoryFactory | ||
| 469 | */ | ||
| 470 | STRIGI_ANALYZER_FACTORY(Factory) |
|   | |||
| 1 | /* This file is part of Strigi Desktop Search | ||
| 2 | * | ||
| 3 | * Copyright (C) 2009 Evgeny Egorochkin <phreedom.stdin@gmail.com> | ||
| 4 | * | ||
| 5 | * This library is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Library General Public | ||
| 7 | * License as published by the Free Software Foundation; either | ||
| 8 | * version 2 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This library is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * Library General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Library General Public License | ||
| 16 | * along with this library; see the file COPYING.LIB. If not, write to | ||
| 17 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 18 | * Boston, MA 02110-1301, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define STRIGI_IMPORT_API | ||
| 22 | #include <strigi/analyzerplugin.h> | ||
| 23 | #include <strigi/streamendanalyzer.h> | ||
| 24 | #include <strigi/analysisresult.h> | ||
| 25 | #include <strigi/fieldtypes.h> | ||
| 26 | #include <strigi/textutils.h> | ||
| 27 | #include <strigi/rdfnamespaces.h> | ||
| 28 | #include <xine.h> | ||
| 29 | #include <cstring> | ||
| 30 | #include <iostream> | ||
| 31 | using namespace Strigi; | ||
| 32 | using namespace std; | ||
| 33 | |||
| 34 | class XineEndAnalyzerFactory; | ||
| 35 | |||
| 36 | class STRIGI_PLUGIN_API XineEndAnalyzer : public StreamEndAnalyzer { | ||
| 37 | private: | ||
| 38 | AnalysisResult* result; | ||
| 39 | const XineEndAnalyzerFactory* factory; | ||
| 40 | xine_t *engine; | ||
| 41 | xine_audio_port_t *audiodrv; | ||
| 42 | xine_video_port_t *videodrv; | ||
| 43 | |||
| 44 | public: | ||
| 45 | XineEndAnalyzer(const XineEndAnalyzerFactory* f) :factory(f) { | ||
| 46 | if ((engine = xine_new())) { | ||
| 47 | xine_init(engine); | ||
| 48 | |||
| 49 | audiodrv = xine_open_audio_driver(engine, NULL, NULL); | ||
| 50 | videodrv = xine_open_video_driver(engine, NULL, XINE_VISUAL_TYPE_NONE, NULL); | ||
| 51 | |||
| 52 | if (!audiodrv || !videodrv) | ||
| 53 | xine_exit (engine); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | ~XineEndAnalyzer() { | ||
| 58 | if (engine) { | ||
| 59 | if (audiodrv) | ||
| 60 | xine_close_audio_driver(engine, audiodrv); | ||
| 61 | if (videodrv) | ||
| 62 | xine_close_video_driver(engine, videodrv); | ||
| 63 | xine_exit(engine); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | const char* name() const { | ||
| 68 | return "XineEndAnalyzer"; | ||
| 69 | } | ||
| 70 | bool checkHeader(const char* header, int32_t headersize) const; | ||
| 71 | signed char analyze(AnalysisResult& idx, ::InputStream* in); | ||
| 72 | }; | ||
| 73 | |||
| 74 | class STRIGI_PLUGIN_API XineEndAnalyzerFactory : public StreamEndAnalyzerFactory { | ||
| 75 | friend class XineEndAnalyzer; | ||
| 76 | private: | ||
| 77 | StreamEndAnalyzer* newInstance() const { | ||
| 78 | return new XineEndAnalyzer(this); | ||
| 79 | } | ||
| 80 | const char* name() const { | ||
| 81 | return "XineEndAnalyzer"; | ||
| 82 | } | ||
| 83 | void registerFields(FieldRegister& ); | ||
| 84 | |||
| 85 | const RegisteredField* durationProperty; | ||
| 86 | const RegisteredField* widthProperty; | ||
| 87 | const RegisteredField* heightProperty; | ||
| 88 | const RegisteredField* frameRateProperty; | ||
| 89 | const RegisteredField* codecProperty; | ||
| 90 | const RegisteredField* bitrateProperty; | ||
| 91 | const RegisteredField* channelsProperty; | ||
| 92 | const RegisteredField* samplerateProperty; | ||
| 93 | const RegisteredField* titleProperty; | ||
| 94 | const RegisteredField* commentProperty; | ||
| 95 | const RegisteredField* typeProperty; | ||
| 96 | }; | ||
| 97 | |||
| 98 | const string | ||
| 99 | videoClassName = | ||
| 100 | NFO "Video", | ||
| 101 | audioClassName = | ||
| 102 | NFO "Audio", | ||
| 103 | musicPieceClassName = | ||
| 104 | NMM_DRAFT "MusicPiece", | ||
| 105 | |||
| 106 | titlePropertyName = | ||
| 107 | NIE "title", | ||
| 108 | commentPropertyName = | ||
| 109 | NIE "comment", | ||
| 110 | |||
| 111 | sampleratePropertyName = | ||
| 112 | NFO "sampleRate", | ||
| 113 | codecPropertyName = | ||
| 114 | NFO "codec", | ||
| 115 | channelsPropertyName = | ||
| 116 | NFO "channels", | ||
| 117 | bitratePropertyName = | ||
| 118 | NFO "averageBitrate", | ||
| 119 | durationPropertyName = | ||
| 120 | NFO "duration", | ||
| 121 | widthPropertyName = | ||
| 122 | NFO "width", | ||
| 123 | heightPropertyName = | ||
| 124 | NFO "height", | ||
| 125 | frameRatePropertyName = | ||
| 126 | NFO "frameRate"; | ||
| 127 | |||
| 128 | void | ||
| 129 | XineEndAnalyzerFactory::registerFields(FieldRegister& r) { | ||
| 130 | durationProperty = r.registerField(durationPropertyName); | ||
| 131 | widthProperty = r.registerField(widthPropertyName); | ||
| 132 | heightProperty = r.registerField(heightPropertyName); | ||
| 133 | frameRateProperty = r.registerField(frameRatePropertyName); | ||
| 134 | codecProperty = r.registerField(codecPropertyName); | ||
| 135 | bitrateProperty = r.registerField(bitratePropertyName); | ||
| 136 | typeProperty = r.typeField; | ||
| 137 | channelsProperty = r.registerField(channelsPropertyName); | ||
| 138 | samplerateProperty = r.registerField(sampleratePropertyName); | ||
| 139 | titleProperty = r.registerField(titlePropertyName); | ||
| 140 | commentProperty = r.registerField(commentPropertyName); | ||
| 141 | } | ||
| 142 | |||
| 143 | //Have to detect here all supported formats because there's no way to pass this to xine | ||
| 144 | bool | ||
| 145 | XineEndAnalyzer::checkHeader(const char* header, int32_t headersize) const { | ||
| 146 | return headersize>=12 && ( | ||
| 147 | !strncmp(header, "FLV", 3) // FLV | ||
| 148 | || readLittleEndianUInt32(header) == 0x75b22630 // ASF/WMA/WMV | ||
| 149 | || (!strncmp(header, "RIFF", 4) && !strncmp(header+8, "AVI ", 4)) // AVI | ||
| 150 | || readLittleEndianUInt32(header) == 0xa3df451a // Matroska/MKV/MKA | ||
| 151 | || !strncmp(header+4, "ftyp3gp", 7) // 3GPP | ||
| 152 | || !strncmp(header+4, "ftypisom", 8) || !strncmp(header+4, "ftypmp42", 8) // MOV | ||
| 153 | || !strncmp(header+4, "ftypMSNV", 8) || !strncmp(header+4, "ftypM4", 6) // MOV | ||
| 154 | || (!strncmp(header, "OggS", 4) && strncmp(header+29, "vorbis", 6)) // Any ogg apart from Vorbis, which is handled by an internal analyzer | ||
| 155 | || readLittleEndianUInt32(header) == 0x10ff3f47 // MPG | ||
| 156 | || readLittleEndianUInt32(header) == 0xb3010000 // MPG | ||
| 157 | || readLittleEndianUInt32(header) == 0xba010000 // MPG | ||
| 158 | ); | ||
| 159 | } | ||
| 160 | |||
| 161 | /* | ||
| 162 | Left unused: | ||
| 163 | XINE_STREAM_INFO_SEEKABLE | ||
| 164 | XINE_STREAM_INFO_VIDEO_RATIO | ||
| 165 | XINE_STREAM_INFO_VIDEO_CHANNELS | ||
| 166 | XINE_STREAM_INFO_VIDEO_STREAMS | ||
| 167 | XINE_STREAM_INFO_VIDEO_FOURCC | ||
| 168 | XINE_STREAM_INFO_VIDEO_HANDLED | ||
| 169 | XINE_STREAM_INFO_AUDIO_BITS | ||
| 170 | XINE_STREAM_INFO_AUDIO_FOURCC | ||
| 171 | XINE_STREAM_INFO_AUDIO_HANDLED | ||
| 172 | XINE_STREAM_INFO_HAS_CHAPTERS | ||
| 173 | XINE_STREAM_INFO_IGNORE_VIDEO | ||
| 174 | XINE_STREAM_INFO_IGNORE_AUDIO | ||
| 175 | XINE_STREAM_INFO_IGNORE_SPU | ||
| 176 | XINE_STREAM_INFO_VIDEO_HAS_STILL | ||
| 177 | XINE_STREAM_INFO_MAX_AUDIO_CHANNEL | ||
| 178 | XINE_STREAM_INFO_MAX_SPU_CHANNEL | ||
| 179 | XINE_STREAM_INFO_AUDIO_MODE | ||
| 180 | XINE_STREAM_INFO_SKIPPED_FRAMES | ||
| 181 | XINE_STREAM_INFO_DISCARDED_FRAMES | ||
| 182 | XINE_STREAM_INFO_VIDEO_AFD | ||
| 183 | XINE_STREAM_INFO_DVD_TITLE_NUMBER | ||
| 184 | XINE_STREAM_INFO_DVD_TITLE_COUNT | ||
| 185 | XINE_STREAM_INFO_DVD_CHAPTER_NUMBER | ||
| 186 | XINE_STREAM_INFO_DVD_CHAPTER_COUNT | ||
| 187 | XINE_STREAM_INFO_DVD_ANGLE_NUMBER | ||
| 188 | XINE_STREAM_INFO_DVD_ANGLE_COUNT | ||
| 189 | |||
| 190 | XINE_META_INFO_ARTIST | ||
| 191 | XINE_META_INFO_GENRE | ||
| 192 | XINE_META_INFO_ALBUM | ||
| 193 | XINE_META_INFO_YEAR | ||
| 194 | XINE_META_INFO_SYSTEMLAYER | ||
| 195 | XINE_META_INFO_INPUT_PLUGIN | ||
| 196 | XINE_META_INFO_CDINDEX_DISCID | ||
| 197 | XINE_META_INFO_TRACK_NUMBER | ||
| 198 | */ | ||
| 199 | |||
| 200 | signed char | ||
| 201 | XineEndAnalyzer::analyze(AnalysisResult& ar, ::InputStream* in) { | ||
| 202 | |||
| 203 | xine_stream_t *stream; | ||
| 204 | |||
| 205 | int posstream, postime, lengthtime; | ||
| 206 | |||
| 207 | string filename; | ||
| 208 | |||
| 209 | if ((ar.depth()==0) && (ar.path().substr(0,7) == "file://")) | ||
| 210 | filename = ar.path().substr(7); | ||
| 211 | else | ||
| 212 | filename = ar.path(); | ||
| 213 | |||
| 214 | if (!(stream = xine_stream_new(engine, audiodrv, videodrv))) | ||
| 215 | return -1; | ||
| 216 | |||
| 217 | if (!xine_open(stream, filename.c_str())) { | ||
| 218 | xine_dispose(stream); | ||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | bool audio = xine_get_stream_info(stream, XINE_STREAM_INFO_HAS_AUDIO); | ||
| 223 | |||
| 224 | if (xine_get_pos_length(stream, &posstream, &postime, &lengthtime)) { | ||
| 225 | if (lengthtime > 0) | ||
| 226 | ar.addValue(factory->durationProperty, lengthtime / 1000); //duration in seconds | ||
| 227 | } | ||
| 228 | |||
| 229 | int bitrate = xine_get_stream_info (stream, XINE_STREAM_INFO_BITRATE); | ||
| 230 | if (bitrate > 0) | ||
| 231 | ar.addValue(factory->bitrateProperty, bitrate); | ||
| 232 | |||
| 233 | // video properties | ||
| 234 | |||
| 235 | if ( xine_get_stream_info(stream, XINE_STREAM_INFO_HAS_VIDEO) ) { | ||
| 236 | ar.addValue(factory->typeProperty, videoClassName); | ||
| 237 | |||
| 238 | int width = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_WIDTH); | ||
| 239 | int height = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_HEIGHT); | ||
| 240 | if (width > 0 && height > 0) { | ||
| 241 | ar.addValue(factory->widthProperty, width); | ||
| 242 | ar.addValue(factory->heightProperty, height); | ||
| 243 | } | ||
| 244 | |||
| 245 | int duration = xine_get_stream_info(stream, XINE_STREAM_INFO_FRAME_DURATION); | ||
| 246 | if ( duration > 0) | ||
| 247 | ar.addValue(factory->frameRateProperty, 90000 / duration); | ||
| 248 | |||
| 249 | const char *videocodec = xine_get_meta_info(stream, XINE_META_INFO_VIDEOCODEC); | ||
| 250 | if (videocodec) | ||
| 251 | ar.addValue(factory->codecProperty, videocodec, strlen(videocodec)); | ||
| 252 | |||
| 253 | // Somehow bitrate always ends up being 0 :( | ||
| 254 | int bitrate = xine_get_stream_info (stream, XINE_STREAM_INFO_VIDEO_BITRATE); | ||
| 255 | if (bitrate > 0) | ||
| 256 | ar.addValue(factory->bitrateProperty, bitrate); | ||
| 257 | } else if (audio) { | ||
| 258 | ar.addValue(factory->typeProperty, musicPieceClassName); | ||
| 259 | ar.addValue(factory->typeProperty, audioClassName); | ||
| 260 | } | ||
| 261 | |||
| 262 | // audio properties | ||
| 263 | |||
| 264 | if (audio) { | ||
| 265 | // Somehow bitrate always ends up being 0 :( | ||
| 266 | int bitrate = xine_get_stream_info (stream, XINE_STREAM_INFO_AUDIO_BITRATE); | ||
| 267 | if (bitrate > 0) | ||
| 268 | ar.addValue(factory->bitrateProperty, bitrate); | ||
| 269 | |||
| 270 | const char *audiocodec = xine_get_meta_info(stream, XINE_META_INFO_AUDIOCODEC); | ||
| 271 | if (audiocodec) | ||
| 272 | ar.addValue(factory->codecProperty, audiocodec, strlen(audiocodec)); | ||
| 273 | |||
| 274 | int channels = xine_get_stream_info(stream, XINE_STREAM_INFO_AUDIO_CHANNELS); | ||
| 275 | if (channels>0) | ||
| 276 | ar.addValue(factory->channelsProperty, channels); | ||
| 277 | |||
| 278 | int samplerate = xine_get_stream_info(stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE); | ||
| 279 | if (samplerate>0) | ||
| 280 | ar.addValue(factory->samplerateProperty, samplerate); | ||
| 281 | } | ||
| 282 | |||
| 283 | // tags | ||
| 284 | |||
| 285 | const char *title = xine_get_meta_info(stream, XINE_META_INFO_TITLE); | ||
| 286 | if (title) | ||
| 287 | ar.addValue(factory->titleProperty, title); | ||
| 288 | |||
| 289 | const char *comment = xine_get_meta_info(stream, XINE_META_INFO_COMMENT); | ||
| 290 | if (comment) | ||
| 291 | ar.addValue(factory->commentProperty, comment); | ||
| 292 | |||
| 293 | xine_dispose(stream); | ||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | |||
| 297 | /* | ||
| 298 | For plugins, we need to have a way to find out which plugins are defined in a | ||
| 299 | plugin. One instance of AnalyzerFactoryFactory per plugin profides this | ||
| 300 | information. | ||
| 301 | */ | ||
| 302 | class Factory : public AnalyzerFactoryFactory { | ||
| 303 | public: | ||
| 304 | list<StreamEndAnalyzerFactory*> | ||
| 305 | streamEndAnalyzerFactories() const { | ||
| 306 | list<StreamEndAnalyzerFactory*> af; | ||
| 307 | af.push_back(new XineEndAnalyzerFactory()); | ||
| 308 | return af; | ||
| 309 | } | ||
| 310 | }; | ||
| 311 | |||
| 312 | /* | ||
| 313 | Register the AnalyzerFactoryFactory | ||
| 314 | */ | ||
| 315 | STRIGI_ANALYZER_FACTORY(Factory) |
|   | |||
| 57 | 57 | // only use this analyzer if the file has been deterined to be c/c++ | |
| 58 | 58 | // this is not accurate at all but better than what we had before | |
| 59 | 59 | ready = i->mimeType() != "text/x-csrc" | |
| 60 | && i->mimeType() != "text/x-chrd" | ||
| 60 | && i->mimeType() != "text/x-chdr" | ||
| 61 | 61 | && i->mimeType() != "text/x-c++src" | |
| 62 | && i->mimeType() != "text/x-c++hrd"; | ||
| 62 | && i->mimeType() != "text/x-c++hdr"; | ||
| 63 | 63 | } | |
| 64 | 64 | void | |
| 65 | 65 | CppLineAnalyzer::handleLine(const char* data, uint32_t length) { |
|   | |||
| 132 | 132 | readPixelFormat ( InputStream* in, DDSPixelFormat & pf ) | |
| 133 | 133 | { | |
| 134 | 134 | const char* c; | |
| 135 | |||
| 135 | |||
| 136 | 136 | if (4 != in->read(c, 4, 4)) | |
| 137 | 137 | return false; | |
| 138 | 138 | pf.size = readLittleEndianUInt32(c); | |
| … | … | ||
| 191 | 191 | ||
| 192 | 192 | return true; | |
| 193 | 193 | } | |
| 194 | |||
| 194 | |||
| 195 | 195 | bool | |
| 196 | 196 | readHeader(InputStream* in, DDSHeader& header) | |
| 197 | 197 | { | |
| … | … | ||
| 233 | 233 | ||
| 234 | 234 | if (!readPixelFormat( in, header.pf)) | |
| 235 | 235 | return false; | |
| 236 | |||
| 237 | 236 | ||
| 237 | |||
| 238 | 238 | if (!readCaps ( in, header.caps)) | |
| 239 | 239 | return false; | |
| 240 | 240 | ||
| … | … | ||
| 257 | 257 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height"); | |
| 258 | 258 | volumeDepthField = reg.registerField( "http://strigi.sf.net/ontologies/homeless#ddsVolumeDepth"); | |
| 259 | 259 | bitDepthField = reg.registerField( | |
| 260 | "http://www.semanticdesktop.org/ontologies/nfo#colorDepth"); | ||
| 260 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorDepth"); | ||
| 261 | 261 | mipmapCountField = reg.registerField("http://strigi.sf.net/ontologies/homeless#ddsMipmapCount"); | |
| 262 | 262 | typeField = reg.registerField("http://strigi.sf.net/ontologies/homeless#ddsImageType"); | |
| 263 | 263 | colorModeField = reg.registerField( | |
| … | … | ||
| 290 | 290 | ||
| 291 | 291 | //Remember: dds files are little-endian | |
| 292 | 292 | //read the beginning of the stream and make sure it looks ok | |
| 293 | |||
| 293 | |||
| 294 | 294 | if (4 != in->read(c, 4, 4)) { | |
| 295 | 295 | in->reset(0); // rewind to the start of the stream | |
| 296 | 296 | return in; |
|   | |||
| 76 | 76 | void | |
| 77 | 77 | GifThroughAnalyzerFactory::registerFields(FieldRegister& reg) { | |
| 78 | 78 | colorDepthField = reg.registerField( | |
| 79 | "http://www.semanticdesktop.org/ontologies/nfo#colorDepth"); | ||
| 79 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorDepth"); | ||
| 80 | 80 | widthField = reg.registerField( | |
| 81 | 81 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#width"); | |
| 82 | 82 | heightField = reg.registerField( |
|   | |||
| 41 | 41 | numberField = reg.registerField( | |
| 42 | 42 | "http://strigi.sf.net/ontologies/homeless#documentImageCount"); | |
| 43 | 43 | bitsPerPixelField = reg.registerField( | |
| 44 | "http://www.semanticdesktop.org/ontologies/nfo#colorDepth"); | ||
| 44 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorDepth"); | ||
| 45 | 45 | colorCountField = reg.registerField( | |
| 46 | 46 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorCount"); | |
| 47 | 47 | ||
| … | … | ||
| 65 | 65 | ||
| 66 | 66 | const char *c; | |
| 67 | 67 | int32_t n; | |
| 68 | |||
| 68 | |||
| 69 | 69 | // Remember: ICO files are little-endian | |
| 70 | 70 | // read the beginning of the stream and make sure it looks ok | |
| 71 | |||
| 71 | |||
| 72 | 72 | n = in->read(c, 6, 6); | |
| 73 | 73 | if (n != 6) { | |
| 74 | 74 | in->reset(0); // rewind to the start of the stream | |
| … | … | ||
| 154 | 154 | analysisResult->addValue( factory->colorCountField, icoe_colorcount ); | |
| 155 | 155 | else if (icoe_bitcount > 0) | |
| 156 | 156 | analysisResult->addValue( factory->colorCountField, 2 ^ icoe_bitcount ); | |
| 157 | |||
| 157 | |||
| 158 | 158 | in->reset(0); // rewind to the start of the stream | |
| 159 | 159 | return in; | |
| 160 | 160 | } |
|   | |||
| 41 | 41 | vResolutionField = reg.registerField( | |
| 42 | 42 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#verticalResolution"); | |
| 43 | 43 | colorDepthField = reg.registerField( | |
| 44 | "http://www.semanticdesktop.org/ontologies/nfo#colorDepth"); | ||
| 44 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorDepth"); | ||
| 45 | 45 | typeField = reg.typeField; | |
| 46 | 46 | ||
| 47 | 47 | addField(compressionField); | |
| … | … | ||
| 70 | 70 | in->reset(0); | |
| 71 | 71 | if (nread < nreq) return in; | |
| 72 | 72 | // check header for some magic bytes and determine if it is valid pcx file | |
| 73 | if (header[0]!=10 || header[1]>5 || header[1]==1 || header[2]>1 || | ||
| 73 | if (header[0]!=10 || header[1]>5 || header[1]==1 || header[2]>1 || | ||
| 74 | 74 | header[3]>8 || header[3]==3 || (header[3]>4 && header[3]<8) || header[64]!=0) return in; | |
| 75 | 75 | // header should be padded to 128 bytes with zeros | |
| 76 | 76 | for (int i=74;i<128;i++) if (header[i]!=0) return in; | |
| 77 | |||
| 77 | |||
| 78 | 78 | int w = ( readLittleEndianUInt16(header+8)-readLittleEndianUInt16(header+4) ) + 1; | |
| 79 | 79 | int h = ( readLittleEndianUInt16(header+10)-readLittleEndianUInt16(header+6) ) + 1; | |
| 80 | 80 | int bpp = header[3]*header[65]; |
|   | |||
| 26 | 26 | #include <strigi/fieldtypes.h> | |
| 27 | 27 | #include <cstring> | |
| 28 | 28 | #include <map> | |
| 29 | //#include <config.h> | ||
| 30 | 29 | ||
| 31 | 30 | using namespace std; | |
| 32 | 31 | using namespace Strigi; | |
| … | … | ||
| 43 | 43 | heightField = reg.registerField( | |
| 44 | 44 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height"); | |
| 45 | 45 | bitDepthField = reg.registerField( | |
| 46 | "http://www.semanticdesktop.org/ontologies/nfo#colorDepth"); | ||
| 46 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorDepth"); | ||
| 47 | 47 | imageNameField = reg.registerField( | |
| 48 | 48 | "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#title"); | |
| 49 | 49 | sharedRowsField = reg.registerField( | |
| … | … | ||
| 110 | 110 | if (dimension == 1) | |
| 111 | 111 | ysize = 1; | |
| 112 | 112 | ||
| 113 | // report analysis | ||
| 113 | // report analysis | ||
| 114 | 114 | analysisResult->addValue( factory->widthField, xsize ); | |
| 115 | 115 | analysisResult->addValue( factory->heightField, ysize ); | |
| 116 | 116 | analysisResult->addValue( factory->bitDepthField, zsize * 8 * bpc ); |
|   | |||
| 34 | 34 | compressionField = reg.registerField( | |
| 35 | 35 | "http://freedesktop.org/standards/xesam/1.0/core#compressionAlgorithm"); | |
| 36 | 36 | colorDepthField = reg.registerField( | |
| 37 | "http://www.semanticdesktop.org/ontologies/nfo#colorDepth"); | ||
| 37 | "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#colorDepth"); | ||
| 38 | 38 | colorModeField = reg.registerField( | |
| 39 | 39 | "http://freedesktop.org/standards/xesam/1.0/core#colorSpace"); | |
| 40 | 40 | widthField = reg.registerField( |
|   | |||
| 167 | 167 | if (StreamBase<T>::m_status == Error) return -2; | |
| 168 | 168 | // check to see if we have this position | |
| 169 | 169 | int64_t d = StreamBase<T>::m_position - newpos; | |
| 170 | if (buffer.readPos - d >= buffer.start && -d < buffer.avail) { | ||
| 170 | if (buffer.readPos >= buffer.start + d && -d <= buffer.avail) { | ||
| 171 | 171 | StreamBase<T>::m_position -= d; | |
| 172 | 172 | buffer.avail += (int32_t)d; | |
| 173 | 173 | buffer.readPos -= d; |
|   | |||
| 51 | 51 | FileInputStream(FILE* file, const char* filepath, | |
| 52 | 52 | int32_t buffersize=defaultBufferSize); | |
| 53 | 53 | ~FileInputStream(); | |
| 54 | |||
| 55 | enum StreamTypeHint { | ||
| 56 | /** let the system choose the most appropriate type **/ | ||
| 57 | Automatic, | ||
| 58 | /** use an internal buffer, can be slow when skipping in large files **/ | ||
| 59 | Buffered, | ||
| 60 | /** do not use an internal buffer, faster for most use cases **/ | ||
| 61 | Unbuffered, | ||
| 62 | /** use mmap for reading the files, falls back to unbuffered when not | ||
| 63 | available **/ | ||
| 64 | MMap | ||
| 65 | }; | ||
| 66 | |||
| 67 | /** | ||
| 68 | * @brief Create an InputStream to access a file | ||
| 69 | * | ||
| 70 | * @param filepath the name of the file to open | ||
| 71 | * @param buffersize the size of the buffer to use, if applicable | ||
| 72 | * @param hint preferred type of stream | ||
| 73 | * @return opened input stream to the file, caller has responsibility to | ||
| 74 | * delete it | ||
| 75 | */ | ||
| 76 | static InputStream* open(const char* filepath, | ||
| 77 | StreamTypeHint hint = Automatic, | ||
| 78 | int32_t buffersize = defaultBufferSize); | ||
| 54 | 79 | }; | |
| 55 | 80 | ||
| 56 | 81 | } // end namespace Strigi |
|   | |||
| 22 | 22 | ||
| 23 | 23 | #include <cstdlib> | |
| 24 | 24 | #include <cstring> | |
| 25 | #include <cassert> | ||
| 25 | 26 | ||
| 26 | 27 | namespace Strigi { | |
| 27 | 28 | ||
| … | … | ||
| 123 | 123 | StreamBuffer<T>::setSize(int32_t size) { | |
| 124 | 124 | // store pointer information | |
| 125 | 125 | int32_t offset = (int32_t)(readPos - start); | |
| 126 | assert(size >= 0); | ||
| 127 | assert(avail >= 0); | ||
| 128 | assert(offset >= 0); | ||
| 129 | assert(avail+offset <= size); // catch broken offset and avail values when shrinking the buffer | ||
| 126 | 130 | ||
| 127 | 131 | // allocate memory in the buffer | |
| 128 | 132 | start = (T*)std::realloc(start, size*sizeof(T)); | |
| … | … | ||
| 141 | 141 | // determine how much space is available for writing | |
| 142 | 142 | int32_t offset = (int32_t)(readPos - start); | |
| 143 | 143 | int32_t space = size - offset - avail; | |
| 144 | |||
| 145 | assert(offset >= 0); | ||
| 146 | assert(size >= 0); | ||
| 147 | assert(avail >= 0); | ||
| 148 | assert(avail+offset <= size); | ||
| 149 | |||
| 144 | 150 | if (space >= needed) { | |
| 145 | 151 | // there's enough space | |
| 146 | 152 | return space; | |
| … | … | ||
| 177 | 177 | template <class T> | |
| 178 | 178 | int32_t | |
| 179 | 179 | StreamBuffer<T>::read(const T*& start, int32_t max) { | |
| 180 | assert(size >= 0); | ||
| 181 | assert(avail >= 0); | ||
| 182 | assert(readPos >= this->start); | ||
| 183 | assert(avail+(readPos-this->start) <= size); | ||
| 184 | |||
| 180 | 185 | start = readPos; | |
| 181 | 186 | if (max <= 0 || max > avail) { | |
| 182 | 187 | max = avail; |
|   | |||
| 18 | 18 | * Boston, MA 02110-1301, USA. | |
| 19 | 19 | */ | |
| 20 | 20 | #include <strigi/fileinputstream.h> | |
| 21 | #include "mmapfileinputstream.h" | ||
| 22 | #include "skippingfileinputstream.h" | ||
| 23 | #include "skippingfileinputstream2.h" | ||
| 21 | 24 | #include <config.h> | |
| 22 | 25 | #include <strigi/strigiconfig.h> | |
| 23 | 26 | #include <iostream> | |
| … | … | ||
| 114 | 114 | } | |
| 115 | 115 | //cerr << "read " << nwritten << " bytes of\t" << filepath << endl; | |
| 116 | 116 | return nwritten; | |
| 117 | } | ||
| 118 | InputStream* | ||
| 119 | FileInputStream::open(const char* filepath, StreamTypeHint hint, | ||
| 120 | int32_t buffersize) { | ||
| 121 | switch (hint) { | ||
| 122 | case Buffered: | ||
| 123 | return new FileInputStream(filepath, buffersize); | ||
| 124 | case MMap: | ||
| 125 | #ifndef _WIN32 | ||
| 126 | return new MMapFileInputStream(filepath); | ||
| 127 | #endif | ||
| 128 | case Unbuffered: | ||
| 129 | case Automatic: | ||
| 130 | default: | ||
| 131 | return new SkippingFileInputStream(filepath); | ||
| 132 | } | ||
| 117 | 133 | } |
|   | |||
| 30 | 30 | using namespace Strigi; | |
| 31 | 31 | using namespace std; | |
| 32 | 32 | ||
| 33 | MMapFileInputStream::MMapFileInputStream(const char* filepath) :p(0) { | ||
| 33 | MMapFileInputStream::MMapFileInputStream(const char* filepath) { | ||
| 34 | 34 | int fd = ::open(filepath, O_RDONLY); | |
| 35 | 35 | struct stat sb; | |
| 36 | 36 | if (fd == -1 || fstat(fd, &sb) == -1) { |
|   | |||
| 27 | 27 | /** | |
| 28 | 28 | * @brief Provides buffered access to a file | |
| 29 | 29 | */ | |
| 30 | class STREAMS_EXPORT MMapFileInputStream : public InputStream { | ||
| 30 | class MMapFileInputStream : public InputStream { | ||
| 31 | 31 | private: | |
| 32 | class Private; | ||
| 33 | Private * const p; | ||
| 34 | 32 | const char *buffer; | |
| 35 | 33 | ||
| 36 | 34 | void open(FILE* f, const char* path); |
|   | |||
| 30 | 30 | using namespace Strigi; | |
| 31 | 31 | using namespace std; | |
| 32 | 32 | ||
| 33 | SkippingFileInputStream::SkippingFileInputStream(const char* filepath) :p(0) { | ||
| 33 | SkippingFileInputStream::SkippingFileInputStream(const char* filepath) { | ||
| 34 | 34 | buffer = 0; | |
| 35 | 35 | buffersize = 0; | |
| 36 | 36 | if (filepath == 0) { | |
| … | … | ||
| 48 | 48 | file = f; | |
| 49 | 49 | filepath.assign(path); | |
| 50 | 50 | if (file == 0) { | |
| 51 | cerr << "ohoh" << endl; | ||
| 51 | 52 | // handle error | |
| 52 | 53 | m_error = "Could not read file '"; | |
| 53 | 54 | m_error += filepath; | |
| … | … | ||
| 72 | 72 | if (n == 1) { | |
| 73 | 73 | m_size = -1; | |
| 74 | 74 | fseeko(file, 0, SEEK_SET); | |
| 75 | } else { | ||
| 76 | fclose(file); | ||
| 77 | file = 0; | ||
| 78 | return; | ||
| 79 | 75 | } | |
| 80 | 76 | } | |
| 81 | 77 | } | |
| … | … | ||
| 87 | 87 | } | |
| 88 | 88 | int32_t | |
| 89 | 89 | SkippingFileInputStream::read(const char*& start, int32_t _min, int32_t _max) { | |
| 90 | if (!file) { | ||
| 91 | m_status = Error; | ||
| 92 | return -2; // error | ||
| 93 | } | ||
| 90 | 94 | int32_t n = max(_min, _max); | |
| 91 | 95 | if (n > buffersize) { | |
| 92 | 96 | buffer = (char*)realloc(buffer, n); | |
| … | … | ||
| 118 | 118 | } | |
| 119 | 119 | int64_t | |
| 120 | 120 | SkippingFileInputStream::reset(int64_t pos) { | |
| 121 | if (!file) { | ||
| 122 | m_status = Error; | ||
| 123 | return -2; // error | ||
| 124 | } | ||
| 121 | 125 | if (m_size >= 0 && pos > m_size) pos = m_size; | |
| 122 | 126 | if (fseek(file, pos, SEEK_SET)) { | |
| 123 | 127 | m_status = Error; |
|   | |||
| 25 | 25 | namespace Strigi { | |
| 26 | 26 | ||
| 27 | 27 | /** | |
| 28 | * @brief Provides buffered access to a file | ||
| 28 | * @brief Private class that provides buffered access to a file | ||
| 29 | 29 | */ | |
| 30 | class STREAMS_EXPORT SkippingFileInputStream : public InputStream { | ||
| 30 | class SkippingFileInputStream : public InputStream { | ||
| 31 | 31 | private: | |
| 32 | class Private; | ||
| 33 | Private * const p; | ||
| 34 | 32 | FILE *file; | |
| 35 | 33 | char *buffer; | |
| 36 | 34 | std::string filepath; |
|   | |||
| 32 | 32 | TESTONARCHIVE(ZipInputStream, "a.zip"); | |
| 33 | 33 | ||
| 34 | 34 | // should have at least one stream | |
| 35 | InputStream* file = new FileInputStream("a.zip"); | ||
| 35 | InputStream* file = FileInputStream::open("a.zip"); | ||
| 36 | 36 | const char* data; | |
| 37 | 37 | file->read(data, 500, 500); | |
| 38 | 38 | file->reset(0); |
|   | |||
| 29 | 29 | VERIFY(chdir(argv[1]) == 0); | |
| 30 | 30 | ||
| 31 | 31 | for (int i=0; i<ninputstreamtests; ++i) { | |
| 32 | MMapFileInputStream file("a.zip"); | ||
| 33 | charinputstreamtests[i](&file); | ||
| 32 | InputStream* file = FileInputStream::open("a.zip", FileInputStream::MMap); | ||
| 33 | charinputstreamtests[i](file); | ||
| 34 | delete file; | ||
| 34 | 35 | } | |
| 35 | 36 | return founderrors; | |
| 36 | 37 | } |
|   | |||
| 54 | 54 | ||
| 55 | 55 | #include "unknownsizestream.h" | |
| 56 | 56 | #include <strigi/fileinputstream.h> | |
| 57 | #ifdef _WIN32 | ||
| 58 | #define MMapFileInputStream FileInputStream | ||
| 59 | #else | ||
| 60 | #ifdef STRIGI_INTERNAL_TEST | ||
| 61 | #include "skippingfileinputstream.h" | ||
| 62 | #include "skippingfileinputstream2.h" | ||
| 63 | #include "mmapfileinputstream.h" | ||
| 64 | #endif | ||
| 65 | #define MMapFileInputStream FileInputStream | ||
| 66 | #endif | ||
| 67 | 57 | ||
| 68 | 58 | #define TESTONFILE(CLASS, FILE) \ | |
| 69 | 59 | for (int i=0; i<ninputstreamtests; ++i) { \ | |
| 70 | FileInputStream f1(FILE); \ | ||
| 71 | CLASS s1(&f1); \ | ||
| 60 | InputStream* f = FileInputStream::open(FILE); \ | ||
| 61 | CLASS s1(f); \ | ||
| 72 | 62 | charinputstreamtests[i](&s1); \ | |
| 63 | delete f; \ | ||
| 73 | 64 | \ | |
| 74 | MMapFileInputStream f2(FILE); \ | ||
| 75 | CLASS s2(&f2); \ | ||
| 65 | f = FileInputStream::open(FILE, FileInputStream::Buffered); \ | ||
| 66 | CLASS s2(f); \ | ||
| 76 | 67 | charinputstreamtests[i](&s2); \ | |
| 68 | delete f; \ | ||
| 77 | 69 | \ | |
| 78 | FileInputStream f3(FILE); \ | ||
| 79 | UnknownSizeInputStream u3(&f3); \ | ||
| 70 | f = FileInputStream::open(FILE); \ | ||
| 71 | UnknownSizeInputStream u3(f); \ | ||
| 80 | 72 | CLASS s3(&u3); \ | |
| 81 | 73 | charinputstreamtests[i](&s3); \ | |
| 74 | delete f; \ | ||
| 82 | 75 | \ | |
| 83 | MMapFileInputStream f4(FILE); \ | ||
| 84 | UnknownSizeInputStream u4(&f4); \ | ||
| 85 | CLASS s4(&f4); \ | ||
| 76 | f = FileInputStream::open(FILE, FileInputStream::Buffered); \ | ||
| 77 | UnknownSizeInputStream u4(f); \ | ||
| 78 | CLASS s4(&u4); \ | ||
| 86 | 79 | charinputstreamtests[i](&s4); \ | |
| 80 | delete f; \ | ||
| 87 | 81 | } | |
| 88 | 82 | ||
| 89 | 83 | #define TESTONFILE2(CLASS, ARG, FILE) \ | |
| 90 | 84 | for (int i=0; i<ninputstreamtests; ++i) { \ | |
| 91 | FileInputStream f1(FILE); \ | ||
| 92 | CLASS s1(&f1, ARG); \ | ||
| 85 | InputStream* f = FileInputStream::open(FILE); \ | ||
| 86 | CLASS s1(f, ARG); \ | ||
| 93 | 87 | charinputstreamtests[i](&s1); \ | |
| 88 | delete f; \ | ||
| 94 | 89 | \ | |
| 95 | MMapFileInputStream f2(FILE); \ | ||
| 96 | CLASS s2(&f2, ARG); \ | ||
| 90 | f = FileInputStream::open(FILE, FileInputStream::Buffered); \ | ||
| 91 | CLASS s2(f, ARG); \ | ||
| 97 | 92 | charinputstreamtests[i](&s2); \ | |
| 93 | delete f; \ | ||
| 98 | 94 | \ | |
| 99 | FileInputStream f3(FILE); \ | ||
| 100 | UnknownSizeInputStream u3(&f3); \ | ||
| 95 | f = FileInputStream::open(FILE); \ | ||
| 96 | UnknownSizeInputStream u3(f); \ | ||
| 101 | 97 | CLASS s3(&u3, ARG); \ | |
| 102 | 98 | charinputstreamtests[i](&s3); \ | |
| 99 | delete f; \ | ||
| 103 | 100 | \ | |
| 104 | MMapFileInputStream f4(FILE); \ | ||
| 105 | UnknownSizeInputStream u4(&f4); \ | ||
| 101 | f = FileInputStream::open(FILE, FileInputStream::Buffered); \ | ||
| 102 | UnknownSizeInputStream u4(f); \ | ||
| 106 | 103 | CLASS s4(&u4, ARG); \ | |
| 107 | 104 | charinputstreamtests[i](&s4); \ | |
| 105 | delete f; \ | ||
| 108 | 106 | } | |
| 109 | 107 | ||
| 110 | 108 | #define TESTONARCHIVE(CLASS, FILE) \ | |
| 111 | 109 | for (int i=0; i<nstreamprovidertests; ++i) { \ | |
| 112 | FileInputStream f1(FILE); \ | ||
| 113 | CLASS s1(&f1); \ | ||
| 110 | InputStream* f = FileInputStream::open(FILE); \ | ||
| 111 | CLASS s1(f); \ | ||
| 114 | 112 | streamprovidertests[i](&s1); \ | |
| 113 | delete f; \ | ||
| 115 | 114 | \ | |
| 116 | MMapFileInputStream f2(FILE); \ | ||
| 117 | CLASS s2(&f2); \ | ||
| 115 | f = FileInputStream::open(FILE, FileInputStream::Buffered); \ | ||
| 116 | CLASS s2(f); \ | ||
| 118 | 117 | streamprovidertests[i](&s2); \ | |
| 118 | delete f; \ | ||
| 119 | 119 | \ | |
| 120 | FileInputStream f3(FILE); \ | ||
| 121 | UnknownSizeInputStream u3(&f3); \ | ||
| 120 | f = FileInputStream::open(FILE); \ | ||
| 121 | UnknownSizeInputStream u3(f); \ | ||
| 122 | 122 | CLASS s3(&u3); \ | |
| 123 | 123 | streamprovidertests[i](&s3); \ | |
| 124 | delete f; \ | ||
| 124 | 125 | \ | |
| 125 | MMapFileInputStream f4(FILE); \ | ||
| 126 | UnknownSizeInputStream u4(&f4); \ | ||
| 127 | CLASS s4(&f4); \ | ||
| 126 | f = FileInputStream::open(FILE, FileInputStream::Buffered); \ | ||
| 127 | UnknownSizeInputStream u4(f); \ | ||
| 128 | CLASS s4(&u4); \ | ||
| 128 | 129 | streamprovidertests[i](&s4); \ | |
| 130 | delete f; \ | ||
| 129 | 131 | } | |
| 130 | 132 | ||
| 131 | 133 | #endif |

