├── .gitignore ├── CMakeLists.txt ├── CMakeModules ├── FindLibavutil.cmake ├── FindTesseract.cmake ├── UploadPPA.cmake └── cmake_uninstall.cmake.in ├── COPYING ├── Makefile ├── README ├── README.org ├── configure ├── debian ├── changelog └── copyright ├── doc ├── CMakeLists.txt ├── completion.sh └── vobsub2srt.1 ├── mplayer ├── CMakeLists.txt ├── README ├── mp_msg.c ├── mp_msg.h ├── spudec.c ├── spudec.h ├── unrar_exec.c ├── unrar_exec.h ├── vobsub.c └── vobsub.h ├── packaging ├── vobsub2srt-9999.ebuild ├── vobsub2srt.rb ├── vobsub2srt.spec └── vobsub2srt.spec.rst └── src ├── CMakeLists.txt ├── cmd_options.c++ ├── cmd_options.h++ ├── gen_langcodes.pl ├── langcodes.c++ ├── langcodes.h++ └── vobsub2srt.c++ /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | test/ 3 | /.dput.cf 4 | /doc/vobsub2srt.1.gz 5 | /ppa_config.cmake 6 | /version 7 | /TAGS 8 | *DS_Store -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(vobsub2srt) 2 | 3 | cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR) 4 | 5 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules) 6 | 7 | if(NOT CMAKE_BUILD_TYPE) 8 | set( 9 | CMAKE_BUILD_TYPE 10 | Debug 11 | CACHE 12 | STRING 13 | "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." 14 | FORCE) 15 | endif() 16 | 17 | message(STATUS "Source: ${CMAKE_SOURCE_DIR}") 18 | message(STATUS "Binary: ${CMAKE_BINARY_DIR}") 19 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 20 | 21 | if(${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) 22 | message(FATAL_ERROR "In-source builds are not permitted. Make a separate folder for building:\nmkdir build; cd build; cmake ..\nBefore that, remove the files that cmake just created:\nrm -rf CMakeCache.txt CMakeFiles") 23 | endif() 24 | 25 | if(BUILD_STATIC) 26 | message(WARNING "Building a statically linked version of VobSub2SRT is NOT recommended. You might run into library dependency issues. Please check the README!") 27 | set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) 28 | endif() 29 | 30 | set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) 31 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) 32 | 33 | set(INSTALL_EXECUTABLES_PATH ${CMAKE_INSTALL_PREFIX}/bin) 34 | set(INSTALL_LIBRARIES_PATH ${CMAKE_INSTALL_PREFIX}/lib) 35 | set(INSTALL_HEADERS_PATH ${CMAKE_INSTALL_PREFIX}/include) 36 | set(INSTALL_ETC_PATH ${CMAKE_INSTALL_PREFIX}/etc) 37 | set(INSTALL_PC_PATH ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) 38 | set(INSTALL_DATA_DIR_BASE "${CMAKE_INSTALL_PREFIX}/share" CACHE STRING "Custom data installation directory without suffixes") 39 | set(INSTALL_DOC_DIR_BASE "${INSTALL_DATA_DIR_BASE}/doc" CACHE STRING "Custom doc installation directory without suffixes") 40 | set(INSTALL_DOC_DIR "${INSTALL_DOC_DIR_BASE}/${CMAKE_PROJECT_NAME}" CACHE STRING "Custom doc installation directory") 41 | set(INSTALL_MAN_DIR "${INSTALL_DATA_DIR_BASE}/man/man1" CACHE STRING "Custom manpage installation directory without suffixes") 42 | 43 | install(FILES "${CMAKE_SOURCE_DIR}/debian/copyright" DESTINATION ${INSTALL_DOC_DIR}) 44 | install(FILES "${CMAKE_SOURCE_DIR}/README.org" DESTINATION ${INSTALL_DOC_DIR} RENAME README) 45 | 46 | add_definitions("-DINSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\"") 47 | 48 | include(CheckIncludeFile) 49 | include(CheckCCompilerFlag) 50 | include(CheckCSourceCompiles) 51 | include(CheckCSourceRuns) 52 | include(CheckCXXCompilerFlag) 53 | include(CheckCXXSourceCompiles) 54 | include(CheckCXXSourceRuns) 55 | 56 | set(CMAKE_C_FLAGS "-std=gnu99") 57 | set(CMAKE_CXX_FLAGS "-ansi -pedantic -Wall -Wextra -Wno-long-long") 58 | 59 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -mtune=native -march=native -DNDEBUG -fomit-frame-pointer -ffast-math") # TODO -Ofast GCC 4.6 60 | set(CMAKE_C_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) 61 | set(CMAKE_CXX_FLAGS_DEBUG "-g3 -DDEBUG") 62 | set(CMAKE_C_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) 63 | # TODO RelWithDebInfo MinSizeRel? maybe move -march=native -ffast-math etc. to a different build type 64 | 65 | find_package(Threads) 66 | find_package(Tesseract) 67 | 68 | add_subdirectory(mplayer) 69 | add_subdirectory(src) 70 | add_subdirectory(doc) 71 | 72 | #### Detect Version 73 | if(NOT VOBSUB2SRT_VERSION) 74 | if(EXISTS "${vobsub2srt_SOURCE_DIR}/version") 75 | file(READ "${vobsub2srt_SOURCE_DIR}/version" VOBSUB2SRT_VERSION) 76 | string(REGEX REPLACE "\n" "" VOBSUB2SRT_VERSION "${VOBSUB2SRT_VERSION}") 77 | elseif(EXISTS "${vobsub2srt_SOURCE_DIR}/.git") 78 | if(NOT GIT_FOUND) 79 | find_package(Git QUIET) 80 | endif() 81 | if(GIT_FOUND) 82 | execute_process( 83 | COMMAND "${GIT_EXECUTABLE}" describe --tags --dirty --always 84 | WORKING_DIRECTORY "${vobsub2srt_SOURCE_DIR}" 85 | OUTPUT_VARIABLE VOBSUB2SRT_VERSION 86 | RESULT_VARIABLE EXECUTE_GIT 87 | OUTPUT_STRIP_TRAILING_WHITESPACE 88 | ERROR_QUIET) 89 | string(REGEX REPLACE "^v" "" VOBSUB2SRT_VERSION "${VOBSUB2SRT_VERSION}") 90 | endif() 91 | endif() 92 | endif() 93 | 94 | if(NOT VOBSUB2SRT_VERSION) 95 | set(VOBSUB2SRT_VERSION "unknown-dirty") 96 | endif() 97 | 98 | message(STATUS "vobsub2srt version: ${VOBSUB2SRT_VERSION}") 99 | 100 | #### uninstall target 101 | configure_file( 102 | "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/cmake_uninstall.cmake.in" 103 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 104 | IMMEDIATE @ONLY) 105 | 106 | add_custom_target(uninstall 107 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 108 | 109 | #### Package Generation 110 | execute_process ( 111 | COMMAND /usr/bin/dpkg --print-architecture 112 | OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE 113 | RESULT_VARIABLE EXECUTE_RESULT 114 | OUTPUT_STRIP_TRAILING_WHITESPACE 115 | ERROR_QUIET 116 | ) 117 | if(EXECUTE_RESULT) 118 | message(STATUS "dpkg not found: No package generation.") 119 | else() 120 | message(STATUS "Debian architecture: ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") 121 | set(CPACK_GENERATOR "DEB") 122 | set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") 123 | set(CPACK_PACKAGE_VERSION "${VOBSUB2SRT_VERSION}") 124 | set(CPACK_PACKAGE_CONTACT "Rüdiger Sonderfeld ") 125 | set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/ruediger/VobSub2SRT") 126 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Converts VobSub subtitles (.idx/.srt format) into .srt subtitles.") 127 | set(CPACK_PACKAGE_DESCRIPTION "VobSub2SRT is a simple command line program to convert .idx / .sub subtitles\ninto .srt text subtitles by using OCR. It is based on code from the MPlayer\nproject - a really great movie player.\nTesseract is used as OCR software.") 128 | 129 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/debian/copyright") 130 | set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.org") 131 | set(CPACK_STRIP_FILES TRUE) 132 | 133 | set(CPACK_DEBIAN_PACKAGE_SECTION "video") 134 | set(CPACK_DEBIAN_PACKAGE_DEPENDS libtesseract-dev) 135 | set(CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS libavutil-dev libtiff5-dev libtesseract-dev tesseract-ocr-eng cmake pkg-config) 136 | # set(CPACK_DEBIAN_GIT_DCH TRUE) 137 | set(CPACK_DEBIAN_UPDATE_CHANGELOG TRUE) 138 | set(PPA_DEBIAN_VERSION "ppa1") 139 | 140 | include(ppa_config.cmake OPTIONAL) 141 | 142 | set(DPUT_HOST "ppa:ruediger-c-plusplus/vobsub2srt") 143 | 144 | include(CPack) 145 | 146 | if(ENABLE_PPA) 147 | set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "any") # can be build on any system 148 | include(UploadPPA) 149 | endif() 150 | endif() 151 | -------------------------------------------------------------------------------- /CMakeModules/FindLibavutil.cmake: -------------------------------------------------------------------------------- 1 | # Find libavutil (part of ffmpeg) 2 | 3 | include(FindPkgConfig) 4 | pkg_check_modules(Libavutil REQUIRED libavutil) 5 | -------------------------------------------------------------------------------- /CMakeModules/FindTesseract.cmake: -------------------------------------------------------------------------------- 1 | # Tesseract OCR 2 | 3 | if(Tesseract_INCLUDE_DIR AND Tesseract_LIBRARIES) 4 | set(Tesseract_FIND_QUIETLY TRUE) 5 | endif() 6 | 7 | find_path(Tesseract_INCLUDE_DIR tesseract/baseapi.h 8 | HINTS 9 | /usr/include 10 | /usr/local/include) 11 | 12 | find_library(Tesseract_LIBRARIES NAMES tesseract_full tesseract_api tesseract 13 | HINTS 14 | /usr/lib 15 | /usr/local/lib) 16 | 17 | find_library(Tiff_LIBRARY NAMES tiff 18 | HINTS 19 | /usr/lib 20 | /usr/local/lib) 21 | 22 | if(BUILD_STATIC) 23 | # -llept -lgif -lwebp -ltiff -lpng -ljpeg -lz 24 | find_library(Lept_LIBRARY NAMES lept 25 | HINTS 26 | /usr/lib 27 | /usr/local/lib) 28 | 29 | find_library(Webp_LIBRARY NAMES webp 30 | HINTS 31 | /usr/lib 32 | /usr/local/lib) 33 | 34 | find_package(GIF) 35 | find_package(JPEG) 36 | find_package(PNG) 37 | #find_package(TIFF) TODO replace manual find_library call 38 | find_package(ZLIB) 39 | 40 | endif() 41 | 42 | if(TESSERACT_DATA_PATH) 43 | add_definitions(-DTESSERACT_DATA_PATH="${TESSERACT_DATA_PATH}") 44 | endif() 45 | 46 | set(CMAKE_REQUIRED_INCLUDES ${Tesseract_INCLUDE_DIR}) 47 | check_cxx_source_compiles( 48 | "#include \"tesseract/baseapi.h\" 49 | using namespace tesseract; 50 | int main() { 51 | }" 52 | TESSERACT_NAMESPACE) 53 | if(TESSERACT_NAMESPACE) 54 | add_definitions("-DCONFIG_TESSERACT_NAMESPACE") 55 | else() 56 | message(WARNING "You are using an old Tesseract version. Support for Tesseract 2 is deprecated and will be removed in the future!") 57 | endif() 58 | list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES ${Tesseract_INCLUDE_DIR}) 59 | 60 | if(BUILD_STATIC) 61 | set(Tesseract_LIBRARIES ${Tesseract_LIBRARIES} ${Lept_LIBRARY} ${PNG_LIBRARY} ${Tiff_LIBRARY} ${Webp_LIBRARY} ${GIF_LIBRARY} ${JPEG_LIBRARY} ${ZLIB_LIBRARY}) 62 | else() 63 | set(Tesseract_LIBRARIES ${Tesseract_LIBRARIES} ${Tiff_LIBRARY}) 64 | endif() 65 | 66 | include(FindPackageHandleStandardArgs) 67 | 68 | find_package_handle_standard_args(Tesseract DEFAULT_MSG Tesseract_LIBRARIES Tesseract_INCLUDE_DIR) 69 | mark_as_advanced(Tesseract_INCLUDE_DIR Tesseract_LIBRARIES) 70 | -------------------------------------------------------------------------------- /CMakeModules/UploadPPA.cmake: -------------------------------------------------------------------------------- 1 | ## -*- mode:cmake; coding:utf-8; -*- 2 | # Copyright (c) 2010 Daniel Pfeifer 3 | # Changes Copyright (c) 2011 2012 Rüdiger Sonderfeld 4 | # 5 | # UploadPPA.cmake is free software. It comes without any warranty, 6 | # to the extent permitted by applicable law. You can redistribute it 7 | # and/or modify it under the terms of the Do What The Fuck You Want 8 | # To Public License, Version 2, as published by Sam Hocevar. See 9 | # http://sam.zoy.org/wtfpl/COPYING for more details. 10 | # 11 | ## 12 | # Documentation 13 | # 14 | # This CMake module uploads a project to a PPA. It creates all the files 15 | # necessary (similar to CPack) and uses debuild(1) and dput(1) to create the 16 | # package and upload it to a PPA. A PPA is a Personal Package Archive and can 17 | # be used by Debian/Ubuntu or other apt/deb based distributions to install and 18 | # update packages from a remote repository. 19 | # Canonicals Launchpad (http://launchpad.net) is usually used to host PPAs. 20 | # See https://help.launchpad.net/Packaging/PPA for further information 21 | # about PPAs. 22 | # 23 | # UploadPPA.cmake uses similar settings to CPack and the CPack DEB Generator. 24 | # Additionally the following variables are used 25 | # 26 | # CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS to specify build dependencies 27 | # (cmake is added as default) 28 | # CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG should point to a file containing the 29 | # changelog in debian format. If not set it checks whether a file 30 | # debian/changelog exists in the source directory or creates a simply changelog 31 | # file. 32 | # CPACK_DEBIAN_UPDATE_CHANGELOG if set to True then UploadPPA.cmake adds a new 33 | # entry to the changelog with the current version number and distribution name 34 | # (lsb_release -c is used). This can be useful because debuild uses the latest 35 | # version number from the changelog and the version number set in 36 | # CPACK_PACKAGE_VERSION. If they mismatch the creation of the package fails. 37 | # 38 | ## 39 | # Check packages 40 | # 41 | # ./configure -DENABLE_PPA=On 42 | # make dput 43 | # cd build/Debian 44 | # dpkg-source -x vobsub2srt_1.0pre4-ppa1.dsc 45 | # cd vobsub2srt-1.0pre4/ 46 | # debuild -i -us -uc -sa -b 47 | # 48 | # Check the lintian warnings! 49 | # 50 | ## 51 | # TODO 52 | # I plan to add support for git dch (from git-buildpackage) to auto generate 53 | # the changelog. 54 | ## 55 | 56 | find_program(DEBUILD_EXECUTABLE debuild) 57 | find_program(DPUT_EXECUTABLE dput) 58 | 59 | if(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) 60 | return() 61 | endif(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) 62 | 63 | # Strip "-dirty" flag from package version. 64 | # It can be added by, e.g., git describe but it causes trouble with debuild etc. 65 | string(REPLACE "-dirty" "" CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}) 66 | message(STATUS "version: ${CPACK_PACKAGE_VERSION}") 67 | 68 | # DEBIAN/control 69 | # debian policy enforce lower case for package name 70 | # Package: (mandatory) 71 | IF(NOT CPACK_DEBIAN_PACKAGE_NAME) 72 | STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME) 73 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_NAME) 74 | 75 | # Section: (recommended) 76 | IF(NOT CPACK_DEBIAN_PACKAGE_SECTION) 77 | SET(CPACK_DEBIAN_PACKAGE_SECTION "devel") 78 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_SECTION) 79 | 80 | # Priority: (recommended) 81 | IF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) 82 | SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") 83 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) 84 | 85 | if(NOT CPACK_DEBIAN_PACKAGE_MAINTAINER) 86 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT}) 87 | endif() 88 | 89 | if(NOT CPACK_PACKAGE_DESCRIPTION AND EXISTS ${CPACK_PACKAGE_DESCRIPTION_FILE}) 90 | file(STRINGS ${CPACK_PACKAGE_DESCRIPTION_FILE} DESC_LINES) 91 | foreach(LINE ${DESC_LINES}) 92 | set(deb_long_description "${deb_long_description} ${LINE}\n") 93 | endforeach(LINE ${DESC_LINES}) 94 | else() 95 | # add space before each line 96 | string(REPLACE "\n" "\n " deb_long_description " ${CPACK_PACKAGE_DESCRIPTION}") 97 | endif() 98 | 99 | if(PPA_DEBIAN_VERSION) 100 | set(DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}-${PPA_DEBIAN_VERSION}") 101 | else() 102 | message(WARNING "Variable PPA_DEBIAN_VERSION not set! Building 'native' package!") 103 | set(DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}") 104 | endif() 105 | message(STATUS "Debian version: ${DEBIAN_PACKAGE_VERSION}") 106 | 107 | set(DEBIAN_SOURCE_DIR ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${DEBIAN_PACKAGE_VERSION}) 108 | 109 | ############################################################################## 110 | # debian/control 111 | set(debian_control ${DEBIAN_SOURCE_DIR}/debian/control) 112 | list(APPEND CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS cmake) 113 | list(REMOVE_DUPLICATES CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS) 114 | list(SORT CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS) 115 | string(REPLACE ";" ", " build_depends "${CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS}") 116 | string(REPLACE ";" ", " bin_depends "${CPACK_DEBIAN_PACKAGE_DEPENDS}") 117 | file(WRITE ${debian_control} 118 | "Source: ${CPACK_DEBIAN_PACKAGE_NAME}\n" 119 | "Section: ${CPACK_DEBIAN_PACKAGE_SECTION}\n" 120 | "Priority: ${CPACK_DEBIAN_PACKAGE_PRIORITY}\n" 121 | "Maintainer: ${CPACK_DEBIAN_PACKAGE_MAINTAINER}\n" 122 | "Build-Depends: ${build_depends}\n" 123 | "Standards-Version: 3.9.3\n" 124 | "Homepage: ${CPACK_DEBIAN_PACKAGE_HOMEPAGE}\n" 125 | "\n" 126 | "Package: ${CPACK_DEBIAN_PACKAGE_NAME}\n" 127 | "Architecture: ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}\n" 128 | "Depends: ${bin_depends}, \${shlibs:Depends}\n" 129 | "Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n" 130 | "${deb_long_description}" 131 | ) 132 | 133 | foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) 134 | string(TOUPPER ${COMPONENT} UPPER_COMPONENT) 135 | set(DEPENDS "${CPACK_DEBIAN_PACKAGE_NAME}") 136 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) 137 | set(DEPENDS "${DEPENDS}, ${CPACK_DEBIAN_PACKAGE_NAME}-${DEP}") 138 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) 139 | file(APPEND ${debian_control} "\n" 140 | "Package: ${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}\n" 141 | "Architecture: ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}\n" 142 | "Depends: ${DEPENDS}\n" 143 | "Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}" 144 | ": ${CPACK_COMPONENT_${UPPER_COMPONENT}_DISPLAY_NAME}\n" 145 | "${deb_long_description}" 146 | " .\n" 147 | " ${CPACK_COMPONENT_${UPPER_COMPONENT}_DESCRIPTION}\n" 148 | ) 149 | endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) 150 | 151 | ############################################################################## 152 | # debian/copyright 153 | set(debian_copyright ${DEBIAN_SOURCE_DIR}/debian/copyright) 154 | configure_file(${CPACK_RESOURCE_FILE_LICENSE} ${debian_copyright} COPYONLY) 155 | 156 | ############################################################################## 157 | # debian/rules 158 | set(debian_rules ${DEBIAN_SOURCE_DIR}/debian/rules) 159 | file(WRITE ${debian_rules} 160 | "#!/usr/bin/make -f\n" 161 | "\n" 162 | "DEBUG = debug_build\n" 163 | "RELEASE = release_build\n" 164 | "GZIP = gzip\n" 165 | "CFLAGS =\n" 166 | "CPPFLAGS =\n" 167 | "CXXFLAGS =\n" 168 | "FFLAGS =\n" 169 | "LDFLAGS =\n" 170 | "\n" 171 | "configure-debug:\n" 172 | "\tcmake -E make_directory $(DEBUG)\n" 173 | "\tcd $(DEBUG); cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr ..\n" 174 | "\ttouch configure-debug\n" 175 | "\n" 176 | "configure-release:\n" 177 | "\tcmake -E make_directory $(RELEASE)\n" 178 | "\tcd $(RELEASE); cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr ..\n" 179 | "\ttouch configure-release\n" 180 | "\n" 181 | "build: build-arch build-indep\n" # build-indep 182 | "\n" 183 | "build-arch: configure-release\n" # configure-debug 184 | # "\t$(MAKE) --no-print-directory -C $(DEBUG) preinstall\n" 185 | "\t$(MAKE) --no-print-directory -C $(RELEASE) preinstall\n" 186 | "\ttouch build-arch\n" 187 | "\n" 188 | "build-indep: configure-release\n" 189 | "\t$(MAKE) --no-print-directory -C $(RELEASE) documentation\n" 190 | "\ttouch build-indep\n" 191 | "\n" 192 | "binary: binary-arch binary-indep\n" 193 | "\n" 194 | "binary-arch: build-arch\n" 195 | # "\tcd $(DEBUG); cmake -DCOMPONENT=Unspecified -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake\n" 196 | "\tcd $(RELEASE); cmake -DCOMPONENT=Unspecified -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake\n" 197 | "\t$(GZIP) -9 -c debian/changelog > debian/tmp/usr/share/doc/${CMAKE_PROJECT_NAME}/changelog.Debian.gz\n" 198 | "\tcmake -E make_directory debian/tmp/DEBIAN\n" 199 | "\tdpkg-shlibdeps debian/tmp/usr/bin/*\n" 200 | "\tdpkg-gencontrol -p${CPACK_DEBIAN_PACKAGE_NAME} -Pdebian/tmp\n" 201 | "\tdpkg --build debian/tmp ..\n" 202 | ) 203 | 204 | foreach(component ${CPACK_COMPONENTS_ALL}) 205 | string(TOUPPER "${component}" COMPONENT) 206 | if(NOT CPACK_COMPONENT_${COMPONENT}_BINARY_INDEP) 207 | set(path debian/${component}) 208 | file(APPEND ${debian_rules} 209 | # "\tcd $(DEBUG); cmake -DCOMPONENT=${component} -DCMAKE_INSTALL_PREFIX=../${path}/usr -P cmake_install.cmake\n" 210 | "\tcd $(RELEASE); cmake -DCOMPONENT=${component} -DCMAKE_INSTALL_PREFIX=../${path}/usr -P cmake_install.cmake\n" 211 | "\tcmake -E make_directory ${path}/DEBIAN\n" 212 | "\tdpkg-gencontrol -p${CPACK_COMPONENT_${COMPONENT}_DEB_PACKAGE} -P${path}\n" 213 | "\tdpkg --build ${path} ..\n" 214 | ) 215 | endif(NOT CPACK_COMPONENT_${COMPONENT}_BINARY_INDEP) 216 | endforeach(component) 217 | 218 | file(APPEND ${debian_rules} 219 | "\n" 220 | "binary-indep: build-indep\n" 221 | ) 222 | 223 | foreach(component ${CPACK_COMPONENTS_ALL}) 224 | string(TOUPPER "${component}" COMPONENT) 225 | if(CPACK_COMPONENT_${COMPONENT}_BINARY_INDEP) 226 | set(path debian/${component}) 227 | file(APPEND ${debian_rules} 228 | # "\tcd $(DEBUG); cmake -DCOMPONENT=${component} -DCMAKE_INSTALL_PREFIX=../${path}/usr -P cmake_install.cmake\n" 229 | "\tcd $(RELEASE); cmake -DCOMPONENT=${component} -DCMAKE_INSTALL_PREFIX=../${path}/usr -P cmake_install.cmake\n" 230 | "\tcmake -E make_directory ${path}/DEBIAN\n" 231 | "\tdpkg-gencontrol -p${CPACK_COMPONENT_${COMPONENT}_DEB_PACKAGE} -P${path}\n" 232 | "\tdpkg --build ${path} ..\n" 233 | ) 234 | endif(CPACK_COMPONENT_${COMPONENT}_BINARY_INDEP) 235 | endforeach(component) 236 | 237 | file(APPEND ${debian_rules} 238 | "\n" 239 | "clean:\n" 240 | "\tcmake -E remove_directory $(DEBUG)\n" 241 | "\tcmake -E remove_directory $(RELEASE)\n" 242 | "\tcmake -E remove configure-debug configure-release build-arch build-indep\n" 243 | "\n" 244 | ".PHONY: binary binary-arch binary-indep clean\n" 245 | ) 246 | 247 | execute_process(COMMAND chmod +x ${debian_rules}) 248 | 249 | ############################################################################## 250 | # debian/compat 251 | file(WRITE ${DEBIAN_SOURCE_DIR}/debian/compat "7") 252 | 253 | ############################################################################## 254 | # debian/source/format 255 | file(WRITE ${DEBIAN_SOURCE_DIR}/debian/source/format "3.0 (quilt)") 256 | 257 | ############################################################################## 258 | # debian/changelog 259 | set(debian_changelog ${DEBIAN_SOURCE_DIR}/debian/changelog) 260 | if(NOT CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG) 261 | set(CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG ${CMAKE_SOURCE_DIR}/debian/changelog) 262 | endif() 263 | 264 | # TODO add support for git dch (git-buildpackage) 265 | 266 | if(EXISTS ${CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG}) 267 | configure_file(${CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG} ${debian_changelog} COPYONLY) 268 | 269 | if(CPACK_DEBIAN_UPDATE_CHANGELOG) 270 | file(READ ${debian_changelog} debian_changelog_content) 271 | execute_process( 272 | COMMAND date -R 273 | OUTPUT_VARIABLE DATE_TIME 274 | OUTPUT_STRIP_TRAILING_WHITESPACE) 275 | execute_process( 276 | COMMAND lsb_release -cs 277 | OUTPUT_VARIABLE DISTRI 278 | OUTPUT_STRIP_TRAILING_WHITESPACE) 279 | file(WRITE ${debian_changelog} 280 | "${CPACK_DEBIAN_PACKAGE_NAME} (${DEBIAN_PACKAGE_VERSION}) ${DISTRI}; urgency=low\n\n" 281 | " * Package created with CMake\n\n" 282 | " -- ${CPACK_DEBIAN_PACKAGE_MAINTAINER} ${DATE_TIME}\n\n" 283 | ) 284 | file(APPEND ${debian_changelog} ${debian_changelog_content}) 285 | endif() 286 | 287 | else() 288 | execute_process( 289 | COMMAND date -R 290 | OUTPUT_VARIABLE DATE_TIME 291 | OUTPUT_STRIP_TRAILING_WHITESPACE) 292 | execute_process( 293 | COMMAND lsb_release -cs 294 | OUTPUT_VARIABLE DISTRI 295 | OUTPUT_STRIP_TRAILING_WHITESPACE) 296 | file(WRITE ${debian_changelog} 297 | "${CPACK_DEBIAN_PACKAGE_NAME} (${DEBIAN_PACKAGE_VERSION}) ${DISTRI}; urgency=low\n\n" 298 | " * Package built with CMake\n\n" 299 | " -- ${CPACK_DEBIAN_PACKAGE_MAINTAINER} ${DATE_TIME}\n" 300 | ) 301 | endif() 302 | 303 | ########################################################################## 304 | # .orig.tar.gz 305 | #execute_process(COMMAND date +%y%m%d 306 | # OUTPUT_VARIABLE day_suffix 307 | # OUTPUT_STRIP_TRAILING_WHITESPACE 308 | # ) 309 | 310 | set(CPACK_SOURCE_IGNORE_FILES 311 | "/build/" 312 | "/debian/" 313 | "/.git/" 314 | ".gitignore" 315 | ".dput.cf" 316 | "/test/" 317 | "/packaging/" 318 | "*~") 319 | 320 | set(package_file_name "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}") 321 | 322 | file(WRITE "${CMAKE_BINARY_DIR}/Debian/cpack.cmake" 323 | "set(CPACK_GENERATOR TBZ2)\n" 324 | "set(CPACK_PACKAGE_NAME \"${CPACK_DEBIAN_PACKAGE_NAME}\")\n" 325 | "set(CPACK_PACKAGE_VERSION \"${CPACK_PACKAGE_VERSION}\")\n" 326 | "set(CPACK_PACKAGE_FILE_NAME \"${package_file_name}.orig\")\n" 327 | "set(CPACK_PACKAGE_DESCRIPTION \"${CPACK_PACKAGE_NAME} Source\")\n" 328 | "set(CPACK_IGNORE_FILES \"${CPACK_SOURCE_IGNORE_FILES}\")\n" 329 | "set(CPACK_INSTALLED_DIRECTORIES \"${CPACK_SOURCE_INSTALLED_DIRECTORIES}\")\n" 330 | ) 331 | 332 | set(orig_file "${DEBIAN_SOURCE_DIR}/${package_file_name}.orig.tar.bz2") 333 | add_custom_command(OUTPUT "${orig_file}" 334 | COMMAND cpack --config ./cpack.cmake 335 | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Debian" 336 | ) 337 | 338 | ############################################################################## 339 | # debuild -S 340 | set(DEB_SOURCE_CHANGES 341 | ${CPACK_DEBIAN_PACKAGE_NAME}_${DEBIAN_PACKAGE_VERSION}_source.changes 342 | ) 343 | 344 | add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/Debian/${DEB_SOURCE_CHANGES} 345 | COMMAND ${DEBUILD_EXECUTABLE} -S 346 | WORKING_DIRECTORY ${DEBIAN_SOURCE_DIR} 347 | DEPENDS "${orig_file}" 348 | ) 349 | 350 | ############################################################################## 351 | # dput ppa:your-lp-id/ppa 352 | add_custom_target(dput ${DPUT_EXECUTABLE} ${DPUT_HOST} ${DEB_SOURCE_CHANGES} 353 | DEPENDS ${CMAKE_BINARY_DIR}/Debian/${DEB_SOURCE_CHANGES} 354 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian 355 | ) 356 | -------------------------------------------------------------------------------- /CMakeModules/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 3 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | 5 | cmake_policy(SET CMP0007 OLD) # ignore empty list elements 6 | 7 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 8 | string(REGEX REPLACE "\n" ";" files "${files}") 9 | list(REVERSE files) 10 | foreach (file ${files}) 11 | message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 12 | if (EXISTS "$ENV{DESTDIR}${file}") 13 | execute_process( 14 | COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" 15 | OUTPUT_VARIABLE rm_out 16 | RESULT_VARIABLE rm_retval 17 | ) 18 | if(NOT ${rm_retval} EQUAL 0) 19 | message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 20 | endif (NOT ${rm_retval} EQUAL 0) 21 | else (EXISTS "$ENV{DESTDIR}${file}") 22 | message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 23 | endif (EXISTS "$ENV{DESTDIR}${file}") 24 | endforeach(file) 25 | 26 | set(INSTALL_DOC_DIR @INSTALL_DOC_DIR@) 27 | if(INSTALL_DOC_DIR) # prevent empty variable! 28 | message(STATUS "Uninstalling \"$ENV{DESTDIR}${INSTALL_DOC_DIR}\"") 29 | # Call rmdir instead of cmake -E remove_directory to avoid removing non-empty 30 | # directories in case install_share_doc points to a common directory 31 | execute_process( 32 | COMMAND rmdir -- "$ENV{DESTDIR}${INSTALL_DOC_DIR}" 33 | OUTPUT_VARIABLE rm_out 34 | RESULT_VARIABLE rm_retval 35 | ) 36 | if(NOT rm_retval EQUAL 0) 37 | message(FATAL_ERROR "Removing directory $ENV{DESTDIR}${INSTALL_DOC_DIR}") 38 | endif() 39 | else() 40 | message(WARNING "No share/doc path found!") 41 | endif() 42 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean distclean install uninstall package dput documentation 2 | 3 | all: build 4 | $(MAKE) -C build 5 | 6 | clean: build 7 | $(MAKE) -C build clean 8 | 9 | distclean: 10 | rm -rf build/ 11 | 12 | documentation: build 13 | $(MAKE) -C build documentation 14 | 15 | install: build 16 | $(MAKE) -C build install 17 | 18 | uninstall: build 19 | $(MAKE) -C build uninstall 20 | 21 | package: build 22 | $(MAKE) -C build package 23 | 24 | dput: 25 | @if [ -d build/Debian ]; then \ 26 | git dch --snapshot --since=465fa781b93e66cfb7080c55880969cb4631d584; \ 27 | $(MAKE) -C build dput; \ 28 | else \ 29 | echo 'Use ./configure -DENABLE_PPA=True to activate PPA support.'; \ 30 | fi 31 | 32 | build: 33 | @echo "Please run ./configure (with appropriate parameters)!" 34 | @exit 1 35 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.org -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | # -*- mode:org; mode:auto-fill; fill-column:80; coding:utf-8; -*- 2 | VobSub2SRT is a simple command line program to convert =.idx= / =.sub= subtitles 3 | into =.srt= text subtitles by using OCR. It is based on code from the 4 | [[http://www.mplayerhq.hu][MPlayer project]] - a really really great movie player. Some minor parts are 5 | copied from [[http://ffmpeg.org/][ffmpeg/avutil]] headers. [[http://code.google.com/p/tesseract-ocr/][Tesseract]] is used as OCR software. 6 | 7 | vobsub2srt is released under the GPL3+ license. The MPlayer code included is 8 | GPL2+ licensed. 9 | 10 | The quality of the OCR depends on the text in the subtitles. Currently the code 11 | does not use any preprocessing. But I'm currently looking into adding filters 12 | and scaling options to improve the OCR. You can correct mistakes in the =.srt= 13 | files with a text editor or a special subtitle editor. 14 | 15 | * Building 16 | You need tesseract. You also need cmake and a gcc to build it. 17 | With Ubuntu 12.10 you can install the dependencies with 18 | 19 | #+BEGIN_EXAMPLE 20 | sudo apt-get install libtiff5-dev libtesseract-dev tesseract-ocr-eng build-essential cmake pkg-config 21 | #+END_EXAMPLE 22 | 23 | You should also install the tesseract data for the languages you want to use! 24 | Note that the support for tesseract 2 is deprecated and will be removed in the 25 | future! 26 | 27 | #+BEGIN_EXAMPLE 28 | ./configure 29 | make 30 | sudo make install 31 | #+END_EXAMPLE 32 | 33 | This should install the program vobsub2srt to =/usr/local/bin=. You can 34 | uninstall vobsub2srt with =sudo make uninstall=. 35 | ** Static binary 36 | I recommend using the dynamic binary! However if you really need a static binary 37 | you can add the flag =-DBUILD_STATIC=ON= to the =./configure= call. But be 38 | aware that building static binaries can be quite troublesome. You need the 39 | static library files for tesseract, libtill, libavutils, and for their 40 | dependencies as well. On Ubuntu 12.04 the static libraries are only included in 41 | the dev packages! You probably also need the Gold linker. 42 | 43 | For Ubuntu 12.04 you need the following extra packages: 44 | 45 | #+BEGIN_EXAMPLE 46 | sudo apt-get install libleptonica-dev libpng12-dev libwebp-dev libgif-dev zlib1g-dev libjpeg-dev binutils-gold 47 | #+END_EXAMPLE 48 | 49 | If linking fails with undefined references then checking what other dependencies 50 | your version of leptonica has is a good starting point. You can do this by 51 | running =ldd /usr/lib/liblept.so= (or whatever the path to leptonica is on your 52 | system). Add those dependencies to =CMakeModules/FindTesseract.cmake=. 53 | 54 | ** Ubuntu PPA and .deb packages 55 | I have created a [[https://launchpad.net/~ruediger-c-plusplus/+archive/vobsub2srt][PPA (Personal Package Archive)]] to make installation on 56 | Ubuntu easy. Simply add the PPA to your apt-get sources and run an update and 57 | you can install the =vobsub2srt= package: 58 | 59 | #+BEGIN_EXAMPLE 60 | sudo add-apt-repository ppa:ruediger-c-plusplus/vobsub2srt 61 | sudo apt-get update 62 | sudo apt-get install vobsub2srt 63 | #+END_EXAMPLE 64 | 65 | *** .deb (Debian/Ubuntu) 66 | You can build a *.deb package (Debian/Ubuntu) with =make package=. The package 67 | is created in the =build= directory. 68 | 69 | You can also create a source package and upload it to your own PPA by using the 70 | =UploadPPA.cmake=. But this is only recommended for people experienced with 71 | cmake and creating Debian packages. 72 | 73 | ** Homebrew 74 | Vobsub2srt contains a formula for [[http://mxcl.github.com/homebrew/][Homebrew]] (a package manager for OS X). It can 75 | be installed by using the following commands: 76 | 77 | #+BEGIN_EXAMPLE 78 | brew install --with-all-languages tesseract 79 | brew install --HEAD https://github.com/ruediger/VobSub2SRT/raw/master/packaging/vobsub2srt.rb 80 | #+END_EXAMPLE 81 | 82 | ** Gentoo ebuild 83 | An [[http://en.wikipedia.org/wiki/Ebuild][ebuild]] for Gentoo Linux is also available. You can make it available to 84 | emerge with the following steps 85 | 86 | #+BEGIN_EXAMPLE 87 | sudo mkdir -p /usr/local/portage/media-video/vobsub2srt/ 88 | wget https://github.com/ruediger/VobSub2SRT/raw/master/packaging/vobsub2srt-9999.ebuild 89 | sudo mv vobsub2srt-9999.ebuild /usr/local/portage/media-video/vobsub2srt/ 90 | cd /usr/local/portage/media-video/vobsub2srt/ 91 | sudo ebuild vobsub2srt-999.ebuild digest 92 | #+END_EXAMPLE 93 | 94 | You should be able to install vobsub2srt with =emerge vobsub2srt= now. If you 95 | want to use a newer version (3+) of tesseract you have to use layman. 96 | See [[https://github.com/ruediger/VobSub2SRT/issues/13][#13]] for details. 97 | ** Arch AUR 98 | There also exist a [[https://wiki.archlinux.org/index.php/PKGBUILD][PKGBUILD]] file for Arch Linux in AUR: 99 | https://aur.archlinux.org/packages/vobsub2srt-git 100 | * Usage 101 | vobsub2srt converts subtitles in VobSub (=.idx= / =.sub=) format into subtitles 102 | in =.srt= format. VobSub subtitles consist of two or three files called 103 | =Filename.idx=, =Filename.sub= and optional =Filename.ifo=. To convert subtitles 104 | simply call 105 | 106 | #+BEGIN_EXAMPLE 107 | vobsub2srt Filename 108 | #+END_EXAMPLE 109 | 110 | with =Filename= being the file name of the subtitle files *WITHOUT* the 111 | extension (=.idx= / =.sub=). vobsub2srt writes the subtitles to a file called 112 | =Filename.srt=. 113 | 114 | If a subtitle file contains more than one language you can use the =--lang= 115 | parameter to set the correct language (Use =--langlist= to find out about the 116 | languages in the file). For some languages you might need to set the tesseract 117 | language yourself (e.g., chi_tra/chi_sim for traditional or simplified chinese 118 | characters). You can use =--tesseract-lang= to do this. In most cases this 119 | should however be autodetected. 120 | 121 | If you want to dump the subtitles as images (e.g. to check for correct ocr) you 122 | can use the =--dump-images= flag. 123 | 124 | Use =--help= or read the manpage to get more information about the options of 125 | vobsub2srt. 126 | 127 | * Bug reports 128 | Please submit bug reports or feature requests to the 129 | [[https://github.com/ruediger/VobSub2SRT/issues][issue tracker on GitHub]]. If you do not have a GitHub account and feel 130 | uncomfortable creating one then feel free to send an e-mail to 131 | instead. 132 | 133 | If you have problems with a specific subtitle file then please check if 134 | it works in mplayer first. If it does not then please report the bug to 135 | mplayer as well and link to the mplayer bug report. 136 | 137 | For bug reports please run =vobsub2srt= with the =--verbose= option and copy 138 | and paste the full output to the bug report. 139 | 140 | * Contributors 141 | Most code is from the MPlayer project. 142 | - Armin Häberling wrote a patch to fix an issue with 143 | multiple instances of the same subtitle in result file (21af426) 144 | - James Harris wrote the formula for Homebrew (54f311d6) 145 | - Leo Koppelkamm reported and fixed issue #5 and problems with long filenames 146 | (b903074c, 36ec8da, d3602d6) 147 | - Till Korten wrote the ebuild script (#13) 148 | - Andreasf fixed missing libavutil include path (3a175eb, #15) 149 | - Michal Gawlik fixed the overlapping issue (5b2ccabc55f, #29, #32) 150 | - "bit" made sure no trailing whitespace are written to the SRT (3a59dc278abc2, #38) 151 | - Baudouin Raoult for various fixes (028f742, #44, b722a03, #42, 7293ac2, #40) 152 | - Justyn Butler added the y-threshold support (f873761, #43) 153 | - James Laird-Wah added min-width/height support and fixed other issues (41c6844, #48, #46) 154 | - Filirom1 fixed a minor issue (4ed58c2, #49) 155 | * To Do 156 | - implement preprocessing (first step scaling. Code available in =spudec.c=) 157 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # -*- mode:sh; coding:utf-8; -*- 3 | 4 | mkdir -p build 5 | cd build && cmake "$@" .. 6 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | vobsub2srt (0.0ubuntu1~1.gbpdb8f2d) UNRELEASED; urgency=low 2 | 3 | ** SNAPSHOT build @db8f2d14276aba886292eb13d48ac05ef1f34bcf ** 4 | 5 | [ Rüdiger Sonderfeld ] 6 | * FinLibavutil: added comment 7 | * added detection and linking for Tesseract 8 | * added more code to extract spu and made spudec.h c++ compat 9 | * Tesseract: search and link libtiff 10 | * ignore test dir for now 11 | * added function to extract the required data from spudec_handle_t 12 | * finished basic structure 13 | * build: added install 14 | * added GPL3+ license header and fixed bug in tesseract usage 15 | * added GPL3+ text 16 | * added README 17 | * R: comments to mark changes from original MPlayer code 18 | * cleaned up the dump_pgm code 19 | * added code to handle cmd args 20 | * improved error message when files not found 21 | * fixed critical mistake ++j vs ++i 22 | * mplayer: fixed vobsub_set_from_lang api (const correctness) 23 | * added --lang flag and code to set the correct language stream and tesseract test data (required ISO 639-1 to ISO 639-3 conversion) 24 | * try to set correct tesseract lang for default stream 25 | * dump_images: use XXX as subtitle id 26 | * should be --dump-images and not --dump_images 27 | * updated README 28 | * added --tesseract-data to set the tesseract data path from the cmd 29 | * print text only when verbose is set 30 | * improved error message when OCR failed 31 | * added GPL3+ header to langcodes.?++ 32 | * moved cmd_options into own code file 33 | * use start_pts from the subfile and not the time stamp from the idx file. 34 | * changed README to org-mode 35 | * README: minor org-mode fix 36 | * README: minor fix (big) 37 | * README: another minor fix (missing == tags) 38 | * updated README 39 | * added manpage vobsub2srt(1) 40 | * install manpage 41 | * updated README (manpage) 42 | 43 | [ Armin Häberling ] 44 | * fix issue with multiple instances of the same subtitle in result file. 45 | 46 | [ Rüdiger Sonderfeld ] 47 | * README: added Contributors (Armin) 48 | * added missing libtiff4-dev dependency 49 | * fixed bug in cmd_options (wasn't relevant for vobsub2srt though) 50 | * Made VobSub2SRT work with Tesseract 3.00. 51 | * forgot to replace Flusspferd with VobSub2SRT 52 | * cmake: fixed Hints (FindTesseract) 53 | * build: added support to build *.deb (Debian/Ubuntu etc.) package (make package) 54 | * README: added make package 55 | * added libtesseract_api as alternative to _full (for tesseract 3.0 support) and changed TESSERACT_NAMESPACE flag to CONFIG_TESSERACT_NAMESPACE 56 | * added support for an ocr blacklist 57 | * added --blacklist documentation 58 | * build/deb: changed version number to prevent problems with dpkg 59 | 60 | [ James Harris ] 61 | * Added Homebrew formula for easy OS X installation. 62 | 63 | [ Rüdiger Sonderfeld ] 64 | * mplayer code: merged spudec.c changes from mplayer trunk. 65 | * stop if .srt file can not be opened 66 | * doc: Added information about the Homebrew formula. 67 | * added James Harris to the Contributors (Homebrew formula) 68 | * build: added version detection 69 | 70 | [ Leo Koppelkamm ] 71 | * Fix issue with some sub files 72 | * Switch off unnecessary messages: 73 | * fix an issue with long directory names 74 | 75 | [ Rüdiger Sonderfeld ] 76 | * Keep in sync with mplayer: Fix typos. 77 | * Keep in sync with mplayer: vobsub: simplify timestamp parsing. 78 | * Keep in sync with mplayer: vobsub: simplify origin parsing. 79 | * README: added Leo Koppelkamm to the list of contributors 80 | * build: apparently tesseract on Ubuntu 11.10 uses threads. CMake now links thread libraries. 81 | * build: prepared for UploadPPA.cmake 82 | 83 | -- Rüdiger Sonderfeld Wed, 16 Nov 2011 01:16:16 +0100 84 | 85 | vobsub2srt (0.0) oneiric; urgency=low 86 | 87 | * Initial 88 | 89 | -- Rüdiger Sonderfeld Mon, 14 Nov 2011 01:35:36 +0100 90 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package is fetched from https://github.com/ruediger/VobSub2SRT. 2 | 3 | Licenses: 4 | GPLv2+: 5 | This package is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | MPlayer 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 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with MPlayer; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | On Debian systems, the complete text of the GNU General 20 | Public License can be found in `/usr/share/common-licenses/GPL-2'. 21 | 22 | GPLv3+: 23 | This program is free software: you can redistribute it and/or modify 24 | it under the terms of the GNU General Public License as published by 25 | the Free Software Foundation, either version 3 of the License, or 26 | (at your option) any later version. 27 | 28 | This program is distributed in the hope that it will be useful, 29 | but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | GNU General Public License for more details. 32 | 33 | You should have received a copy of the GNU General Public License 34 | along with this program. If not, see . 35 | 36 | On Debian systems, the complete text of the GNU General 37 | Public License can be found in `/usr/share/common-licenses/GPL-3'. 38 | 39 | Licenses, upstream authors and copyright holders: 40 | 41 | mplayer part 42 | License: GPLv2+ 43 | Copyright (C) 2005 Jindrich Makovicka 44 | Copyright (C) 2007 Ulion 45 | Copyright (C) 2005 Jindrich Makovicka 46 | Copyright (C) 2007 Ulion 47 | 48 | vobsub2srt part 49 | License: GPLv3+ 50 | Copyright (C) 2010-2016 Rüdiger Sonderfeld 51 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_program(GZIP gzip 2 | HINTS 3 | /bin 4 | /usr/bin 5 | /usr/local/bin) 6 | 7 | if(GZIP-NOTFOUND) 8 | message(WARNING "Gzip not found! Uncompressed manpage installed") 9 | add_custom_target(documentation ALL 10 | DEPENDS vobsub2srt.1) 11 | 12 | install(FILES vobsub2srt.1 DESTINATION ${INSTALL_MAN_DIR}) 13 | else() 14 | add_custom_command( 15 | OUTPUT ${CMAKE_BINARY_DIR}/doc/vobsub2srt.1.gz 16 | COMMAND ${GZIP} -9 -c vobsub2srt.1 > ${CMAKE_BINARY_DIR}/doc/vobsub2srt.1.gz 17 | MAIN_DEPENDENCY vobsub2srt.1 18 | WORKING_DIRECTORY "${vobsub2srt_SOURCE_DIR}/doc") 19 | 20 | add_custom_target(documentation ALL 21 | DEPENDS ${CMAKE_BINARY_DIR}/doc/vobsub2srt.1.gz) 22 | 23 | install(FILES ${CMAKE_BINARY_DIR}/doc/vobsub2srt.1.gz DESTINATION ${INSTALL_MAN_DIR}) 24 | endif() 25 | 26 | #option(BASH_COMPLETION_PATH "Install the bash completion script to the given path. Should be set to the value of `pkg-config --variable=completionsdir bash-completion` if available.") 27 | 28 | if(NOT BASH_COMPLETION_PATH) 29 | # Instead of calling pkg-config it should be possible to use 30 | # find_package(bash-completions). See the bash-completions README. 31 | # But Debian/Ubuntu don't ship the cmake configs at the moment. 32 | # Therefore we fallback to pkg-config. 33 | find_program(PKG_CONFIG_EXECUTABLE NAMES pkg-config DOC "pkg-config executable") 34 | mark_as_advanced(PKG_CONFIG_EXECUTABLE) 35 | if(PKG_CONFIG_EXECUTABLE) 36 | execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=completionsdir bash-completion 37 | OUTPUT_VARIABLE BASH_COMPLETION_PATH 38 | ERROR_QUIET 39 | OUTPUT_STRIP_TRAILING_WHITESPACE) 40 | endif() 41 | endif() 42 | 43 | if(BASH_COMPLETION_PATH) 44 | message(STATUS "Bash completion path: ${BASH_COMPLETION_PATH}") 45 | install(FILES completion.sh DESTINATION ${BASH_COMPLETION_PATH} RENAME vobsub2srt) 46 | else() 47 | message(STATUS "Bash completions not installed (set -DBASH_COMPLETION_PATH)") 48 | endif() 49 | -------------------------------------------------------------------------------- /doc/completion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- mode:sh; coding:utf-8; -*- 3 | # 4 | # Bash completions for vobsub2srt(1). 5 | # 6 | # Copyright (C) 2010-2016 Rüdiger Sonderfeld 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # 21 | 22 | have vobsub2srt && 23 | _vobsub2srt() { 24 | local cmd cur prev tmp arg 25 | cmd=${COMP_WORDS[0]} 26 | _get_comp_words_by_ref cur prev 27 | 28 | case $prev in 29 | --ifo) 30 | _filedir '(ifo|IFO)' 31 | return 0 32 | ;; 33 | --lang|-l) 34 | _get_first_arg 35 | tmp=$( "$cmd" --langlist -- "$arg" 2>/dev/null | sed -E -e '/Languages:/d; s/^[[:digit:]]+: //;' ) 36 | COMPREPLY=( $( compgen -W "$tmp" -- "$cur" ) ) 37 | return 0 38 | ;; 39 | --tesseract-data) 40 | _filedir -d 41 | return 0 42 | ;; 43 | esac 44 | 45 | case $cur in 46 | -*) 47 | COMPREPLY=( $( compgen -W '--dump-images --verbose --ifo --lang --langlist --tesseract-lang --tesseract-data --blacklist --y-threshold --min-width --min-height' -- "$cur" ) ) 48 | ;; 49 | *) 50 | _filedir '(idx|IDX|sub|SUB)' 51 | COMPREPLY=$( echo "$COMPREPLY" | sed -E -e 's/.(idx|IDX|sub|SUB)$//' ) # remove suffix 52 | ;; 53 | esac 54 | 55 | return 0 56 | } && 57 | complete -F _vobsub2srt vobsub2srt 58 | -------------------------------------------------------------------------------- /doc/vobsub2srt.1: -------------------------------------------------------------------------------- 1 | .TH vobsub2srt 1 "17 June 2013" 2 | .SH NAME 3 | vobsub2srt \- converts vobsub (.idx/.sub) into .srt subtitles 4 | .SH SYNOPSIS 5 | \fBvobsub2srt\fR [\fIOPTION\fR] \fIFILENAME\fR 6 | .SH DESCRIPTION 7 | .PP 8 | vobsub2srt converts subtitles in vobsub (.idx/.sub) format into the .srt format. VobSub subtitles contain images and srt is a text format. OCR is used to extract the text from the subtitles. vobsub2srt uses tesseract for OCR and is based on code from the MPlayer project. 9 | .SH OPTIONS 10 | .TP 11 | \fIFILENAME\fR 12 | File name of the subtitles \fBWITHOUT\fR the .idx or .sub extension. The .srt subtitles are written to a file called \fIFILENAME\fR.srt. 13 | .TP 14 | \fB\-\-dump\-images\fR 15 | Dump the subtitles as images (format \fIFILENAME\fR-\fINUMBER\fR.pgm in PGM format). 16 | .TP 17 | \fB\-\-verbose\fR 18 | Print more information about the file (e.g. subtitle languages) 19 | .TP 20 | \fB\-\-lang\fR \fIlanguage\fR 21 | Select the language of the subtitle (two letter ISO 639-1 code e.g. en for English or de for German). Use \fI--langlist\fR to see the languages in the subtitle file. 22 | .TP 23 | \fB\-\-langlist\fR 24 | List languages and exit. 25 | .TP 26 | \fB\-\-index\fR \fIindex\fR 27 | The index of the subtitle to convert. Use this instead \fI--lang\fR if there are several streams with the same language. Combining \fI--lang\fR and \fI--index\fR does not work! 28 | .TP 29 | \fB\-\-ifo\fR \fIifo-file\fR 30 | To use a specific IFO file. Default: \fIFILENAME\fR.IFO is tried. IFO file is optional! 31 | .TP 32 | \fB\-\-tesseract-lang\fR \fIlanguage\fR 33 | Set the language to be used by tesseract. This is auto detected and normally does not has to be changed. If however you need special language settings (e.g., deu-frak, chi_sim, chi_tra) use this option. 34 | .TP 35 | \fB\-\-tesseract-data\fR \fIpath\fR 36 | Set path to tesseract-data. 37 | .TP 38 | \fB\-\-blacklist\fR \fIblacklist\fR 39 | Blacklist characters for OCR (e.g. |\\/`_~<>) 40 | .TP 41 | \fB\-\-y-threshold\fR \fIthreshold\fR 42 | Y (luminance) threshold below which colors treated as black (Default: 0). 43 | .TP 44 | \fB\-\-min-width\fR \fIwidth\fR 45 | Minimum width in pixels to consider a subpicture for OCR (Default: 9). 46 | .TP 47 | \fB\-\-min-height\fR \fIheight\fR 48 | Minimum height in pixels to consider a subpicture for OCR (Default: 1). 49 | .SH EXAMPLES 50 | .nf 51 | $ \fBvobsub2srt \-\-lang en foobar\fR 52 | .fi 53 | Converts the English language subtitles from the VobSub files \fIfoobar.idx\fR/\fIfoobar.sub\fR to srt subtitles in \fIfoobar.srt\fR. 54 | .nf 55 | $ \fBvobsub2srt \-\-lang zh \-\-tesseract-lang chi_sim foobar\fR 56 | .fi 57 | Converts the chinese language subtitles using simplified chinese (chi_sim) characters. 58 | .SH HOMEPAGE 59 | For more information see \fIhttp://github.com/ruediger/VobSub2SRT\fR 60 | .SH AUTHOR 61 | R\[:u]diger Sonderfeld <\fIruediger -AT- c-plusplus -DOT- de\fR> 62 | -------------------------------------------------------------------------------- /mplayer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_definitions("-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_REENTRANT") 2 | add_definitions("-Wundef -Wall -Wno-switch -Wno-parentheses -Wpointer-arith -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -Wdisabled-optimization -Wno-pointer-sign -Wdeclaration-after-statement") 3 | 4 | set(mplayer_sources 5 | mp_msg.c 6 | mp_msg.h 7 | spudec.c 8 | spudec.h 9 | unrar_exec.c 10 | unrar_exec.h 11 | vobsub.c 12 | vobsub.h 13 | ) 14 | 15 | add_library(mplayer STATIC ${mplayer_sources}) 16 | -------------------------------------------------------------------------------- /mplayer/README: -------------------------------------------------------------------------------- 1 | The code in this folder is copied from the MPlayer project (http://www.mplayerhq.hu/). A really great movie player! It is licensed under the GPL2+ license. 2 | 3 | I added comments prefixed with R: to mark changes from the original MPlayer code. 4 | -------------------------------------------------------------------------------- /mplayer/mp_msg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MPlayer. 3 | * 4 | * MPlayer is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MPlayer is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with MPlayer; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #if 0 // R: no iconv, charset stuff 25 | #include "config.h" 26 | #include "osdep/getch2.h" 27 | #endif 28 | 29 | #ifdef CONFIG_ICONV 30 | #include 31 | #include 32 | #endif 33 | 34 | #include "mp_msg.h" 35 | 36 | /* maximum message length of mp_msg */ 37 | #define MSGSIZE_MAX 3072 38 | 39 | int mp_msg_levels[MSGT_MAX]; // verbose level of this module. initialized to -2 40 | int mp_msg_level_all = MSGL_STATUS; 41 | int verbose = 0; 42 | int mp_msg_color = 0; 43 | int mp_msg_module = 0; 44 | #ifdef CONFIG_ICONV 45 | char *mp_msg_charset = NULL; 46 | static char *old_charset = NULL; 47 | static iconv_t msgiconv; 48 | #endif 49 | 50 | const char* filename_recode(const char* filename) 51 | { 52 | #if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET) 53 | return filename; 54 | #else 55 | static iconv_t inv_msgiconv = (iconv_t)(-1); 56 | static char recoded_filename[MSGSIZE_MAX]; 57 | size_t filename_len, max_path; 58 | char* precoded; 59 | if (!mp_msg_charset || 60 | !strcasecmp(mp_msg_charset, MSG_CHARSET) || 61 | !strcasecmp(mp_msg_charset, "noconv")) 62 | return filename; 63 | if (inv_msgiconv == (iconv_t)(-1)) { 64 | inv_msgiconv = iconv_open(MSG_CHARSET, mp_msg_charset); 65 | if (inv_msgiconv == (iconv_t)(-1)) 66 | return filename; 67 | } 68 | filename_len = strlen(filename); 69 | max_path = MSGSIZE_MAX - 4; 70 | precoded = recoded_filename; 71 | if (iconv(inv_msgiconv, &filename, &filename_len, 72 | &precoded, &max_path) == (size_t)(-1) && errno == E2BIG) { 73 | precoded[0] = precoded[1] = precoded[2] = '.'; 74 | precoded += 3; 75 | } 76 | *precoded = '\0'; 77 | return recoded_filename; 78 | #endif 79 | } 80 | 81 | void mp_msg_init(void){ 82 | int i; 83 | #if 0 // R: don't check MPLAYER_VERBOSE environment var 84 | char *env = getenv("MPLAYER_VERBOSE"); 85 | if (env) 86 | verbose = atoi(env); 87 | #endif 88 | for(i=0;i7, c&7, c); 114 | flag = 0; 115 | } 116 | #endif 117 | if (mp_msg_color) 118 | fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7); 119 | } 120 | 121 | static void print_msg_module(FILE* stream, int mod) 122 | { 123 | static const char *module_text[MSGT_MAX] = { 124 | "GLOBAL", 125 | "CPLAYER", 126 | "GPLAYER", 127 | "VIDEOOUT", 128 | "AUDIOOUT", 129 | "DEMUXER", 130 | "DS", 131 | "DEMUX", 132 | "HEADER", 133 | "AVSYNC", 134 | "AUTOQ", 135 | "CFGPARSER", 136 | "DECAUDIO", 137 | "DECVIDEO", 138 | "SEEK", 139 | "WIN32", 140 | "OPEN", 141 | "DVD", 142 | "PARSEES", 143 | "LIRC", 144 | "STREAM", 145 | "CACHE", 146 | "MENCODER", 147 | "XACODEC", 148 | "TV", 149 | "OSDEP", 150 | "SPUDEC", 151 | "PLAYTREE", 152 | "INPUT", 153 | "VFILTER", 154 | "OSD", 155 | "NETWORK", 156 | "CPUDETECT", 157 | "CODECCFG", 158 | "SWS", 159 | "VOBSUB", 160 | "SUBREADER", 161 | "AFILTER", 162 | "NETST", 163 | "MUXER", 164 | "OSDMENU", 165 | "IDENTIFY", 166 | "RADIO", 167 | "ASS", 168 | "LOADER", 169 | "STATUSLINE", 170 | }; 171 | int c2 = (mod + 1) % 15 + 1; 172 | 173 | if (!mp_msg_module) 174 | return; 175 | if (mp_msg_color) 176 | fprintf(stream, "\033[%d;3%dm", c2 >> 3, c2 & 7); 177 | fprintf(stream, "%9s", module_text[mod]); 178 | if (mp_msg_color) 179 | fprintf(stream, "\033[0;37m"); 180 | fprintf(stream, ": "); 181 | } 182 | 183 | void mp_msg(int mod, int lev, const char *format, ... ){ 184 | va_list va; 185 | char tmp[MSGSIZE_MAX]; 186 | FILE *stream = lev <= MSGL_WARN ? stderr : stdout; 187 | static int header = 1; 188 | // indicates if last line printed was a status line 189 | static int statusline; 190 | size_t len; 191 | 192 | if (!mp_msg_test(mod, lev)) return; // do not display 193 | va_start(va, format); 194 | vsnprintf(tmp, MSGSIZE_MAX, format, va); 195 | va_end(va); 196 | tmp[MSGSIZE_MAX-2] = '\n'; 197 | tmp[MSGSIZE_MAX-1] = 0; 198 | 199 | #if defined(CONFIG_ICONV) && defined(MSG_CHARSET) 200 | if (mp_msg_charset && strcasecmp(mp_msg_charset, "noconv")) { 201 | char tmp2[MSGSIZE_MAX]; 202 | size_t inlen = strlen(tmp), outlen = MSGSIZE_MAX; 203 | char *in = tmp, *out = tmp2; 204 | if (!old_charset || strcmp(old_charset, mp_msg_charset)) { 205 | if (old_charset) { 206 | free(old_charset); 207 | iconv_close(msgiconv); 208 | } 209 | msgiconv = iconv_open(mp_msg_charset, MSG_CHARSET); 210 | old_charset = strdup(mp_msg_charset); 211 | } 212 | if (msgiconv == (iconv_t)(-1)) { 213 | fprintf(stderr,"iconv: conversion from %s to %s unsupported\n" 214 | ,MSG_CHARSET,mp_msg_charset); 215 | }else{ 216 | memset(tmp2, 0, MSGSIZE_MAX); 217 | while (iconv(msgiconv, &in, &inlen, &out, &outlen) == -1) { 218 | if (!inlen || !outlen) 219 | break; 220 | *out++ = *in++; 221 | outlen--; inlen--; 222 | } 223 | strncpy(tmp, tmp2, MSGSIZE_MAX); 224 | tmp[MSGSIZE_MAX-1] = 0; 225 | tmp[MSGSIZE_MAX-2] = '\n'; 226 | } 227 | } 228 | #endif 229 | 230 | // as a status line normally is intended to be overwitten by next status line 231 | // output a '\n' to get a normal message on a separate line 232 | if (statusline && lev != MSGL_STATUS) fprintf(stream, "\n"); 233 | statusline = lev == MSGL_STATUS; 234 | 235 | if (header) 236 | print_msg_module(stream, mod); 237 | set_msg_color(stream, lev); 238 | len = strlen(tmp); 239 | header = len && (tmp[len-1] == '\n' || tmp[len-1] == '\r'); 240 | 241 | fprintf(stream, "%s", tmp); 242 | if (mp_msg_color) 243 | fprintf(stream, "\033[0m"); 244 | fflush(stream); 245 | } 246 | -------------------------------------------------------------------------------- /mplayer/mp_msg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MPlayer. 3 | * 4 | * MPlayer is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MPlayer is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with MPlayer; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef MPLAYER_MP_MSG_H 20 | #define MPLAYER_MP_MSG_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | // defined in mplayer.c and mencoder.c 27 | extern int verbose; 28 | 29 | // verbosity elevel: 30 | 31 | /* Only messages level MSGL_FATAL-MSGL_STATUS should be translated, 32 | * messages level MSGL_V and above should not be translated. */ 33 | 34 | #define MSGL_FATAL 0 // will exit/abort 35 | #define MSGL_ERR 1 // continues 36 | #define MSGL_WARN 2 // only warning 37 | #define MSGL_HINT 3 // short help message 38 | #define MSGL_INFO 4 // -quiet 39 | #define MSGL_STATUS 5 // v=0 40 | #define MSGL_V 6 // v=1 41 | #define MSGL_DBG2 7 // v=2 42 | #define MSGL_DBG3 8 // v=3 43 | #define MSGL_DBG4 9 // v=4 44 | #define MSGL_DBG5 10 // v=5 45 | 46 | #define MSGL_FIXME 1 // for conversions from printf where the appropriate MSGL is not known; set equal to ERR for obtrusiveness 47 | #define MSGT_FIXME 0 // for conversions from printf where the appropriate MSGT is not known; set equal to GLOBAL for obtrusiveness 48 | 49 | // code/module: 50 | 51 | #define MSGT_GLOBAL 0 // common player stuff errors 52 | #define MSGT_CPLAYER 1 // console player (mplayer.c) 53 | #define MSGT_GPLAYER 2 // gui player 54 | 55 | #define MSGT_VO 3 // libvo 56 | #define MSGT_AO 4 // libao 57 | 58 | #define MSGT_DEMUXER 5 // demuxer.c (general stuff) 59 | #define MSGT_DS 6 // demux stream (add/read packet etc) 60 | #define MSGT_DEMUX 7 // fileformat-specific stuff (demux_*.c) 61 | #define MSGT_HEADER 8 // fileformat-specific header (*header.c) 62 | 63 | #define MSGT_AVSYNC 9 // mplayer.c timer stuff 64 | #define MSGT_AUTOQ 10 // mplayer.c auto-quality stuff 65 | 66 | #define MSGT_CFGPARSER 11 // cfgparser.c 67 | 68 | #define MSGT_DECAUDIO 12 // av decoder 69 | #define MSGT_DECVIDEO 13 70 | 71 | #define MSGT_SEEK 14 // seeking code 72 | #define MSGT_WIN32 15 // win32 dll stuff 73 | #define MSGT_OPEN 16 // open.c (stream opening) 74 | #define MSGT_DVD 17 // open.c (DVD init/read/seek) 75 | 76 | #define MSGT_PARSEES 18 // parse_es.c (mpeg stream parser) 77 | #define MSGT_LIRC 19 // lirc_mp.c and input lirc driver 78 | 79 | #define MSGT_STREAM 20 // stream.c 80 | #define MSGT_CACHE 21 // cache2.c 81 | 82 | #define MSGT_MENCODER 22 83 | 84 | #define MSGT_XACODEC 23 // XAnim codecs 85 | 86 | #define MSGT_TV 24 // TV input subsystem 87 | 88 | #define MSGT_OSDEP 25 // OS-dependent parts 89 | 90 | #define MSGT_SPUDEC 26 // spudec.c 91 | 92 | #define MSGT_PLAYTREE 27 // Playtree handeling (playtree.c, playtreeparser.c) 93 | 94 | #define MSGT_INPUT 28 95 | 96 | #define MSGT_VFILTER 29 97 | 98 | #define MSGT_OSD 30 99 | 100 | #define MSGT_NETWORK 31 101 | 102 | #define MSGT_CPUDETECT 32 103 | 104 | #define MSGT_CODECCFG 33 105 | 106 | #define MSGT_SWS 34 107 | 108 | #define MSGT_VOBSUB 35 109 | #define MSGT_SUBREADER 36 110 | 111 | #define MSGT_AFILTER 37 // Audio filter messages 112 | 113 | #define MSGT_NETST 38 // Netstream 114 | 115 | #define MSGT_MUXER 39 // muxer layer 116 | 117 | #define MSGT_OSD_MENU 40 118 | 119 | #define MSGT_IDENTIFY 41 // -identify output 120 | 121 | #define MSGT_RADIO 42 122 | 123 | #define MSGT_ASS 43 // libass messages 124 | 125 | #define MSGT_LOADER 44 // dll loader messages 126 | 127 | #define MSGT_STATUSLINE 45 // playback/encoding status line 128 | 129 | #define MSGT_TELETEXT 46 // Teletext decoder 130 | 131 | #define MSGT_MAX 64 132 | 133 | 134 | extern char *mp_msg_charset; 135 | extern int mp_msg_color; 136 | extern int mp_msg_module; 137 | 138 | extern int mp_msg_levels[MSGT_MAX]; 139 | extern int mp_msg_level_all; 140 | 141 | 142 | void mp_msg_init(void); 143 | int mp_msg_test(int mod, int lev); 144 | 145 | //#include "config.h" // R: not needed 146 | 147 | #ifdef __GNUC__ 148 | void mp_msg(int mod, int lev, const char *format, ... ) __attribute__ ((format (printf, 3, 4))); 149 | #if 0 // R: not needed and args... doesn't work with -ansi 150 | # ifdef MP_DEBUG 151 | # define mp_dbg(mod,lev, args... ) mp_msg(mod, lev, ## args ) 152 | # else 153 | # define mp_dbg(mod,lev, args... ) /* only useful for developers */ 154 | # endif 155 | #endif 156 | #else // not GNU C 157 | void mp_msg(int mod, int lev, const char *format, ... ); 158 | # ifdef MP_DEBUG 159 | # define mp_dbg(mod,lev, ... ) mp_msg(mod, lev, __VA_ARGS__) 160 | # else 161 | # define mp_dbg(mod,lev, ... ) /* only useful for developers */ 162 | # endif 163 | #endif /* __GNUC__ */ 164 | 165 | const char* filename_recode(const char* filename); 166 | 167 | #ifdef __cplusplus 168 | } 169 | #endif 170 | 171 | #endif /* MPLAYER_MP_MSG_H */ 172 | -------------------------------------------------------------------------------- /mplayer/spudec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MPlayer. 3 | * 4 | * MPlayer is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MPlayer is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with MPlayer; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef MPLAYER_SPUDEC_H 20 | #define MPLAYER_SPUDEC_H 21 | 22 | //#include "libvo/video_out.h" 23 | #include 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | void spudec_heartbeat(void *self, unsigned int pts100); 31 | void spudec_assemble(void *self, unsigned char *packet, unsigned int len, int pts100); 32 | void spudec_draw(void *self, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); 33 | void spudec_draw_scaled(void *self, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); 34 | int spudec_apply_palette_crop(void *self, uint32_t palette, int sx, int ex, int sy, int ey); 35 | void spudec_update_palette(void *self, unsigned int *palette); 36 | void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len, unsigned int y_threshold); 37 | void *spudec_new(unsigned int *palette, unsigned int y_threshold); 38 | void spudec_free(void *self); 39 | void spudec_reset(void *self); // called after seek 40 | int spudec_visible(void *self); // check if spu is visible 41 | void spudec_set_font_factor(void * self, double factor); // sets the equivalent to ffactor 42 | //void spudec_set_hw_spu(void *self, const vo_functions_t *hw_spu); 43 | int spudec_changed(void *self); 44 | void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox); 45 | void spudec_set_forced_subs_only(void * const self, const unsigned int flag); 46 | void spudec_set_paletted(void *self, const uint8_t *pal_img, int stride, 47 | const void *palette, 48 | int x, int y, int w, int h, 49 | double pts, double endpts); 50 | /// call this after spudec_assemble and spudec_heartbeat to get the packet data 51 | void spudec_get_data(void *self, const unsigned char **image, size_t *image_size, unsigned *width, unsigned *height, 52 | unsigned *stride, unsigned *start_pts, unsigned *end_pts); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif /* MPLAYER_SPUDEC_H */ 59 | -------------------------------------------------------------------------------- /mplayer/unrar_exec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * List files and extract file from rars by using external executable unrar. 3 | * 4 | * Copyright (C) 2005 Jindrich Makovicka 5 | * Copyright (C) 2007 Ulion 6 | * 7 | * This file is part of MPlayer. 8 | * 9 | * MPlayer is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * MPlayer is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License along 20 | * with MPlayer; if not, write to the Free Software Foundation, Inc., 21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "unrar_exec.h" 33 | 34 | #include "mp_msg.h" 35 | 36 | #define UNRAR_LIST 1 37 | #define UNRAR_EXTRACT 2 38 | 39 | char* unrar_executable = NULL; 40 | 41 | static FILE* launch_pipe(pid_t *apid, const char *executable, int action, 42 | const char *archive, const char *filename) 43 | { 44 | if (!executable || access(executable, R_OK | X_OK)) return NULL; 45 | if (access(archive, R_OK)) return NULL; 46 | { 47 | int mypipe[2]; 48 | pid_t pid; 49 | 50 | if (pipe(mypipe)) { 51 | mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Cannot create pipe.\n"); 52 | return NULL; 53 | } 54 | 55 | pid = fork(); 56 | if (pid == 0) { 57 | /* This is the child process. Execute the unrar executable. */ 58 | close(mypipe[0]); 59 | // Close MPlayer's stdin, stdout and stderr so the unrar binary 60 | // can not mess them up. 61 | // TODO: Close all other files except the pipe. 62 | close(0); close(1); close(2); 63 | // Assign new stdin, stdout and stderr and check they actually got the 64 | // right descriptors. 65 | if (open("/dev/null", O_RDONLY) != 0 || dup(mypipe[1]) != 1 66 | || open("/dev/null", O_WRONLY) != 2) 67 | _exit(EXIT_FAILURE); 68 | if (action == UNRAR_LIST) 69 | execl(executable, executable, "v", archive, NULL); 70 | else if (action == UNRAR_EXTRACT) 71 | execl(executable, executable, "p", "-inul", "-p-", 72 | archive,filename,NULL); 73 | mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Cannot execute %s\n", executable); 74 | _exit(EXIT_FAILURE); 75 | } 76 | if (pid < 0) { 77 | /* The fork failed. Report failure. */ 78 | mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Fork failed\n"); 79 | return NULL; 80 | } 81 | /* This is the parent process. Prepare the pipe stream. */ 82 | close(mypipe[1]); 83 | *apid = pid; 84 | if (action == UNRAR_LIST) 85 | mp_msg(MSGT_GLOBAL, MSGL_V, 86 | "UnRAR: call unrar with command line: %s v %s\n", 87 | executable, archive); 88 | else if (action == UNRAR_EXTRACT) 89 | mp_msg(MSGT_GLOBAL, MSGL_V, 90 | "UnRAR: call unrar with command line: %s p -inul -p- %s %s\n", 91 | executable, archive, filename); 92 | return fdopen(mypipe[0], "r"); 93 | } 94 | } 95 | 96 | #define ALLOC_INCR 1 * 1024 * 1024 97 | int unrar_exec_get(unsigned char **output, unsigned long *size, 98 | const char *filename, const char *rarfile) 99 | { 100 | int bufsize = ALLOC_INCR, bytesread; 101 | pid_t pid; 102 | int status = 0; 103 | FILE *rar_pipe; 104 | 105 | rar_pipe=launch_pipe(&pid,unrar_executable,UNRAR_EXTRACT,rarfile,filename); 106 | if (!rar_pipe) return 0; 107 | 108 | *size = 0; 109 | 110 | *output = malloc(bufsize); 111 | 112 | while (*output) { 113 | bytesread=fread(*output+*size, 1, bufsize-*size, rar_pipe); 114 | if (bytesread <= 0) 115 | break; 116 | *size += bytesread; 117 | if (*size == bufsize) { 118 | char *p; 119 | bufsize += ALLOC_INCR; 120 | p = realloc(*output, bufsize); 121 | if (!p) 122 | free(*output); 123 | *output = p; 124 | } 125 | } 126 | fclose(rar_pipe); 127 | pid = waitpid(pid, &status, 0); 128 | if (!*output || !*size || (pid == -1 && errno != ECHILD) || 129 | (pid > 0 && status)) { 130 | free(*output); 131 | *output = NULL; 132 | *size = 0; 133 | return 0; 134 | } 135 | if (bufsize > *size) { 136 | char *p = realloc(*output, *size); 137 | if (p) 138 | *output = p; 139 | } 140 | mp_msg(MSGT_GLOBAL, MSGL_V, "UnRAR: got file %s len %lu\n", filename,*size); 141 | return 1; 142 | } 143 | 144 | #define PARSE_NAME 0 145 | #define PARSE_PROPS 1 146 | 147 | int unrar_exec_list(const char *rarfile, ArchiveList_struct **list) 148 | { 149 | char buf[1024], fname[1024]; 150 | char *p; 151 | pid_t pid; 152 | int status = 0, file_num = -1, ignore_next_line = 0, state = PARSE_NAME; 153 | FILE *rar_pipe; 154 | ArchiveList_struct *alist = NULL, *current = NULL, *new; 155 | 156 | rar_pipe = launch_pipe(&pid, unrar_executable, UNRAR_LIST, rarfile, NULL); 157 | if (!rar_pipe) return -1; 158 | while (fgets(buf, sizeof(buf), rar_pipe)) { 159 | int packsize, unpsize, ratio, day, month, year, hour, min; 160 | int llen = strlen(buf); 161 | // If read nothing, we got a file_num -1. 162 | if (file_num == -1) 163 | file_num = 0; 164 | if (buf[llen-1] != '\n') 165 | // The line is too long, ignore it. 166 | ignore_next_line = 2; 167 | if (ignore_next_line) { 168 | --ignore_next_line; 169 | state = PARSE_NAME; 170 | continue; 171 | } 172 | // Trim the line. 173 | while (llen > 0 && strchr(" \t\n\r\v\f", buf[llen-1])) 174 | --llen; 175 | buf[llen] = '\0'; 176 | p = buf; 177 | while (*p && strchr(" \t\n\r\v\f", *p)) 178 | ++p; 179 | if (!*p) { 180 | state = PARSE_NAME; 181 | continue; 182 | } 183 | 184 | if (state == PARSE_PROPS && sscanf(p, "%d %d %d%% %d-%d-%d %d:%d", 185 | &unpsize, &packsize, &ratio, &day, 186 | &month, &year, &hour, &min) == 8) { 187 | new = calloc(1, sizeof(ArchiveList_struct)); 188 | if (!new) { 189 | file_num = -1; 190 | break; 191 | } 192 | if (!current) 193 | alist = new; 194 | else 195 | current->next = new; 196 | current = new; 197 | current->item.Name = strdup(fname); 198 | state = PARSE_NAME; 199 | if (!current->item.Name) { 200 | file_num = -1; 201 | break; 202 | } 203 | current->item.PackSize = packsize; 204 | current->item.UnpSize = unpsize; 205 | ++file_num; 206 | continue; 207 | } 208 | strcpy(fname, p); 209 | state = PARSE_PROPS; 210 | } 211 | fclose(rar_pipe); 212 | pid = waitpid(pid, &status, 0); 213 | if (file_num < 0 || (pid == -1 && errno != ECHILD) || 214 | (pid > 0 && status)) { 215 | unrar_exec_freelist(alist); 216 | return -1; 217 | } 218 | if (!alist) 219 | return -1; 220 | *list = alist; 221 | mp_msg(MSGT_GLOBAL, MSGL_V, "UnRAR: list got %d files\n", file_num); 222 | return file_num; 223 | } 224 | 225 | void unrar_exec_freelist(ArchiveList_struct *list) 226 | { 227 | ArchiveList_struct* tmp; 228 | 229 | while (list) { 230 | tmp = list->next; 231 | free(list->item.Name); 232 | free(list); 233 | list = tmp; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /mplayer/unrar_exec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * List files and extract file from rars by using external executable unrar. 3 | * 4 | * Copyright (C) 2005 Jindrich Makovicka 5 | * Copyright (C) 2007 Ulion 6 | * 7 | * This file is part of MPlayer. 8 | * 9 | * MPlayer is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * MPlayer is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License along 20 | * with MPlayer; if not, write to the Free Software Foundation, Inc., 21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #ifndef MPLAYER_UNRAR_EXEC_H 25 | #define MPLAYER_UNRAR_EXEC_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | struct RAR_archive_entry 32 | { 33 | char *Name; 34 | unsigned long PackSize; 35 | unsigned long UnpSize; 36 | unsigned long FileCRC; 37 | unsigned long FileTime; 38 | unsigned char UnpVer; 39 | unsigned char Method; 40 | unsigned long FileAttr; 41 | }; 42 | 43 | typedef struct archivelist 44 | { 45 | struct RAR_archive_entry item; 46 | struct archivelist *next; 47 | } ArchiveList_struct; 48 | 49 | extern char* unrar_executable; 50 | 51 | int unrar_exec_get(unsigned char **output, unsigned long *size, 52 | const char *filename, const char *rarfile); 53 | 54 | int unrar_exec_list(const char *rarfile, ArchiveList_struct **list); 55 | 56 | void unrar_exec_freelist(ArchiveList_struct *list); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | 62 | #endif /* MPLAYER_UNRAR_EXEC_H */ 63 | -------------------------------------------------------------------------------- /mplayer/vobsub.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-basic-offset: 4 -*- 2 | * Some code freely inspired from VobSub , 3 | * with kind permission from Gabest 4 | * 5 | * This file is part of MPlayer. 6 | * 7 | * MPlayer is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * MPlayer is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with MPlayer; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | //#include "config.h" 36 | #define CONFIG_UNRAR_EXEC 1 // moved from config.h 37 | //#include "mpcommon.h" 38 | #include "vobsub.h" 39 | #include "spudec.h" 40 | #include "mp_msg.h" 41 | #include "unrar_exec.h" 42 | 43 | // Record the original -vobsubid set by commandline, since vobsub_id will be 44 | // overridden if slang match any of vobsub streams. 45 | static int vobsubid = -2; 46 | 47 | int vobsub_id = 0; // moved from mpcommon.h/mplayer.c 48 | 49 | /********************************************************************** 50 | * RAR stream handling 51 | * The RAR file must have the same basename as the file to open 52 | **********************************************************************/ 53 | #ifdef CONFIG_UNRAR_EXEC 54 | typedef struct { 55 | FILE *file; 56 | unsigned char *data; 57 | unsigned long size; 58 | unsigned long pos; 59 | } rar_stream_t; 60 | 61 | static rar_stream_t *rar_open(const char *const filename, 62 | const char *const mode) 63 | { 64 | rar_stream_t *stream; 65 | /* unrar_exec can only read */ 66 | if (strcmp("r", mode) && strcmp("rb", mode)) { 67 | errno = EINVAL; 68 | return NULL; 69 | } 70 | stream = malloc(sizeof(rar_stream_t)); 71 | if (stream == NULL) 72 | return NULL; 73 | /* first try normal access */ 74 | stream->file = fopen(filename, mode); 75 | if (stream->file == NULL) { 76 | char *rar_filename; 77 | const char *p; 78 | int rc; 79 | /* Guess the RAR archive filename */ 80 | rar_filename = NULL; 81 | p = strrchr(filename, '.'); 82 | if (p) { 83 | ptrdiff_t l = p - filename; 84 | rar_filename = malloc(l + 5); 85 | if (rar_filename == NULL) { 86 | free(stream); 87 | return NULL; 88 | } 89 | strncpy(rar_filename, filename, l); 90 | strcpy(rar_filename + l, ".rar"); 91 | } else { 92 | rar_filename = malloc(strlen(filename) + 5); 93 | if (rar_filename == NULL) { 94 | free(stream); 95 | return NULL; 96 | } 97 | strcpy(rar_filename, filename); 98 | strcat(rar_filename, ".rar"); 99 | } 100 | /* get rid of the path if there is any */ 101 | if ((p = strrchr(filename, '/')) == NULL) { 102 | p = filename; 103 | } else { 104 | p++; 105 | } 106 | rc = unrar_exec_get(&stream->data, &stream->size, p, rar_filename); 107 | if (!rc) { 108 | /* There is no matching filename in the archive. However, sometimes 109 | * the files we are looking for have been given arbitrary names in the archive. 110 | * Let's look for a file with an exact match in the extension only. */ 111 | int i, num_files, name_len; 112 | ArchiveList_struct *list, *lp; 113 | num_files = unrar_exec_list(rar_filename, &list); 114 | if (num_files > 0) { 115 | char *demanded_ext; 116 | demanded_ext = strrchr (p, '.'); 117 | if (demanded_ext) { 118 | int demanded_ext_len = strlen (demanded_ext); 119 | for (i = 0, lp = list; i < num_files; i++, lp = lp->next) { 120 | name_len = strlen (lp->item.Name); 121 | if (name_len >= demanded_ext_len && !strcasecmp (lp->item.Name + name_len - demanded_ext_len, demanded_ext)) { 122 | rc = unrar_exec_get(&stream->data, &stream->size, 123 | lp->item.Name, rar_filename); 124 | if (rc) 125 | break; 126 | } 127 | } 128 | } 129 | unrar_exec_freelist(list); 130 | } 131 | if (!rc) { 132 | free(rar_filename); 133 | free(stream); 134 | return NULL; 135 | } 136 | } 137 | 138 | free(rar_filename); 139 | stream->pos = 0; 140 | } 141 | return stream; 142 | } 143 | 144 | static int rar_close(rar_stream_t *stream) 145 | { 146 | if (stream->file) 147 | return fclose(stream->file); 148 | free(stream->data); 149 | return 0; 150 | } 151 | 152 | static int rar_eof(rar_stream_t *stream) 153 | { 154 | if (stream->file) 155 | return feof(stream->file); 156 | return stream->pos >= stream->size; 157 | } 158 | 159 | static long rar_tell(rar_stream_t *stream) 160 | { 161 | if (stream->file) 162 | return ftell(stream->file); 163 | return stream->pos; 164 | } 165 | 166 | static int rar_seek(rar_stream_t *stream, long offset, int whence) 167 | { 168 | if (stream->file) 169 | return fseek(stream->file, offset, whence); 170 | switch (whence) { 171 | case SEEK_SET: 172 | if (offset < 0) { 173 | errno = EINVAL; 174 | return -1; 175 | } 176 | stream->pos = offset; 177 | break; 178 | case SEEK_CUR: 179 | if (offset < 0 && stream->pos < (unsigned long) -offset) { 180 | errno = EINVAL; 181 | return -1; 182 | } 183 | stream->pos += offset; 184 | break; 185 | case SEEK_END: 186 | if (offset < 0 && stream->size < (unsigned long) -offset) { 187 | errno = EINVAL; 188 | return -1; 189 | } 190 | stream->pos = stream->size + offset; 191 | break; 192 | default: 193 | errno = EINVAL; 194 | return -1; 195 | } 196 | return 0; 197 | } 198 | 199 | static int rar_getc(rar_stream_t *stream) 200 | { 201 | if (stream->file) 202 | return getc(stream->file); 203 | if (rar_eof(stream)) 204 | return EOF; 205 | return stream->data[stream->pos++]; 206 | } 207 | 208 | static size_t rar_read(void *ptr, size_t size, size_t nmemb, 209 | rar_stream_t *stream) 210 | { 211 | size_t res; 212 | unsigned long remain; 213 | if (stream->file) 214 | return fread(ptr, size, nmemb, stream->file); 215 | if (rar_eof(stream)) 216 | return 0; 217 | res = size * nmemb; 218 | remain = stream->size - stream->pos; 219 | if (res > remain) 220 | res = remain / size * size; 221 | memcpy(ptr, stream->data + stream->pos, res); 222 | stream->pos += res; 223 | res /= size; 224 | return res; 225 | } 226 | 227 | #else 228 | typedef FILE rar_stream_t; 229 | #define rar_open fopen 230 | #define rar_close fclose 231 | #define rar_eof feof 232 | #define rar_tell ftell 233 | #define rar_seek fseek 234 | #define rar_getc getc 235 | #define rar_read fread 236 | #endif 237 | 238 | /**********************************************************************/ 239 | 240 | static ssize_t vobsub_getline(char **lineptr, size_t *n, rar_stream_t *stream) 241 | { 242 | size_t res = 0; 243 | int c; 244 | if (*lineptr == NULL) { 245 | *lineptr = malloc(4096); 246 | if (*lineptr) 247 | *n = 4096; 248 | } else if (*n == 0) { 249 | char *tmp = realloc(*lineptr, 4096); 250 | if (tmp) { 251 | *lineptr = tmp; 252 | *n = 4096; 253 | } 254 | } 255 | if (*lineptr == NULL || *n == 0) 256 | return -1; 257 | 258 | for (c = rar_getc(stream); c != EOF; c = rar_getc(stream)) { 259 | if (res + 1 >= *n) { 260 | char *tmp = realloc(*lineptr, *n * 2); 261 | if (tmp == NULL) 262 | return -1; 263 | *lineptr = tmp; 264 | *n *= 2; 265 | } 266 | (*lineptr)[res++] = c; 267 | if (c == '\n') { 268 | (*lineptr)[res] = 0; 269 | return res; 270 | } 271 | } 272 | if (res == 0) 273 | return -1; 274 | (*lineptr)[res] = 0; 275 | return res; 276 | } 277 | 278 | /********************************************************************** 279 | * MPEG parsing 280 | **********************************************************************/ 281 | 282 | typedef struct { 283 | rar_stream_t *stream; 284 | unsigned int pts; 285 | int aid; 286 | unsigned char *packet; 287 | unsigned int packet_reserve; 288 | unsigned int packet_size; 289 | int padding_was_here; 290 | int merge; 291 | } mpeg_t; 292 | 293 | static mpeg_t *mpeg_open(const char *filename) 294 | { 295 | mpeg_t *res = malloc(sizeof(mpeg_t)); 296 | int err = res == NULL; 297 | if (!err) { 298 | res->pts = 0; 299 | res->aid = -1; 300 | res->packet = NULL; 301 | res->packet_size = 0; 302 | res->packet_reserve = 0; 303 | res->padding_was_here = 1; 304 | res->merge = 0; 305 | res->stream = rar_open(filename, "rb"); 306 | err = res->stream == NULL; 307 | if (err) 308 | perror("fopen Vobsub file failed"); 309 | if (err) 310 | free(res); 311 | } 312 | return err ? NULL : res; 313 | } 314 | 315 | static void mpeg_free(mpeg_t *mpeg) 316 | { 317 | if (mpeg->packet) 318 | free(mpeg->packet); 319 | if (mpeg->stream) 320 | rar_close(mpeg->stream); 321 | free(mpeg); 322 | } 323 | 324 | static int mpeg_eof(mpeg_t *mpeg) 325 | { 326 | return rar_eof(mpeg->stream); 327 | } 328 | 329 | static off_t mpeg_tell(mpeg_t *mpeg) 330 | { 331 | return rar_tell(mpeg->stream); 332 | } 333 | 334 | static int mpeg_run(mpeg_t *mpeg) 335 | { 336 | unsigned int len, idx, version; 337 | int c; 338 | /* Goto start of a packet, it starts with 0x000001?? */ 339 | const unsigned char wanted[] = { 0, 0, 1 }; 340 | unsigned char buf[5]; 341 | 342 | mpeg->aid = -1; 343 | mpeg->packet_size = 0; 344 | if (rar_read(buf, 4, 1, mpeg->stream) != 1) 345 | return -1; 346 | while (memcmp(buf, wanted, sizeof(wanted)) != 0) { 347 | c = rar_getc(mpeg->stream); 348 | if (c < 0) 349 | return -1; 350 | memmove(buf, buf + 1, 3); 351 | buf[3] = c; 352 | } 353 | switch (buf[3]) { 354 | case 0xb9: /* System End Code */ 355 | break; 356 | case 0xba: /* Packet start code */ 357 | c = rar_getc(mpeg->stream); 358 | if (c < 0) 359 | return -1; 360 | if ((c & 0xc0) == 0x40) 361 | version = 4; 362 | else if ((c & 0xf0) == 0x20) 363 | version = 2; 364 | else { 365 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Unsupported MPEG version: 0x%02x\n", c); 366 | return -1; 367 | } 368 | if (version == 4) { 369 | if (rar_seek(mpeg->stream, 9, SEEK_CUR)) 370 | return -1; 371 | } else if (version == 2) { 372 | if (rar_seek(mpeg->stream, 7, SEEK_CUR)) 373 | return -1; 374 | } else 375 | abort(); 376 | if (!mpeg->padding_was_here) 377 | mpeg->merge = 1; 378 | break; 379 | case 0xbd: /* packet */ 380 | if (rar_read(buf, 2, 1, mpeg->stream) != 1) 381 | return -1; 382 | mpeg->padding_was_here = 0; 383 | len = buf[0] << 8 | buf[1]; 384 | idx = mpeg_tell(mpeg); 385 | c = rar_getc(mpeg->stream); 386 | if (c < 0) 387 | return -1; 388 | if ((c & 0xC0) == 0x40) { /* skip STD scale & size */ 389 | if (rar_getc(mpeg->stream) < 0) 390 | return -1; 391 | c = rar_getc(mpeg->stream); 392 | if (c < 0) 393 | return -1; 394 | } 395 | if ((c & 0xf0) == 0x20) { /* System-1 stream timestamp */ 396 | /* Do we need this? */ 397 | abort(); 398 | } else if ((c & 0xf0) == 0x30) { 399 | /* Do we need this? */ 400 | abort(); 401 | } else if ((c & 0xc0) == 0x80) { /* System-2 (.VOB) stream */ 402 | unsigned int pts_flags, hdrlen, dataidx; 403 | c = rar_getc(mpeg->stream); 404 | if (c < 0) 405 | return -1; 406 | pts_flags = c; 407 | c = rar_getc(mpeg->stream); 408 | if (c < 0) 409 | return -1; 410 | hdrlen = c; 411 | dataidx = mpeg_tell(mpeg) + hdrlen; 412 | if (dataidx > idx + len) { 413 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "Invalid header length: %d (total length: %d, idx: %d, dataidx: %d)\n", 414 | hdrlen, len, idx, dataidx); 415 | return -1; 416 | } 417 | if ((pts_flags & 0xc0) == 0x80) { 418 | if (rar_read(buf, 5, 1, mpeg->stream) != 1) 419 | return -1; 420 | if (!(((buf[0] & 0xf0) == 0x20) && (buf[0] & 1) && (buf[2] & 1) && (buf[4] & 1))) { 421 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "vobsub PTS error: 0x%02x %02x%02x %02x%02x \n", 422 | buf[0], buf[1], buf[2], buf[3], buf[4]); 423 | mpeg->pts = 0; 424 | } else 425 | mpeg->pts = ((buf[0] & 0x0e) << 29 | buf[1] << 22 | (buf[2] & 0xfe) << 14 426 | | buf[3] << 7 | (buf[4] >> 1)); 427 | } else /* if ((pts_flags & 0xc0) == 0xc0) */ { 428 | /* what's this? */ 429 | /* abort(); */ 430 | } 431 | rar_seek(mpeg->stream, dataidx, SEEK_SET); 432 | mpeg->aid = rar_getc(mpeg->stream); 433 | if (mpeg->aid < 0) { 434 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "Bogus aid %d\n", mpeg->aid); 435 | return -1; 436 | } 437 | mpeg->packet_size = len - ((unsigned int) mpeg_tell(mpeg) - idx); 438 | if (mpeg->packet_reserve < mpeg->packet_size) { 439 | if (mpeg->packet) 440 | free(mpeg->packet); 441 | mpeg->packet = malloc(mpeg->packet_size); 442 | if (mpeg->packet) 443 | mpeg->packet_reserve = mpeg->packet_size; 444 | } 445 | if (mpeg->packet == NULL) { 446 | mp_msg(MSGT_VOBSUB, MSGL_FATAL, "malloc failure"); 447 | mpeg->packet_reserve = 0; 448 | mpeg->packet_size = 0; 449 | return -1; 450 | } 451 | if (rar_read(mpeg->packet, mpeg->packet_size, 1, mpeg->stream) != 1) { 452 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "fread failure"); 453 | mpeg->packet_size = 0; 454 | return -1; 455 | } 456 | idx = len; 457 | } 458 | break; 459 | case 0xbe: /* Padding */ 460 | if (rar_read(buf, 2, 1, mpeg->stream) != 1) 461 | return -1; 462 | len = buf[0] << 8 | buf[1]; 463 | if (len > 0 && rar_seek(mpeg->stream, len, SEEK_CUR)) 464 | return -1; 465 | mpeg->padding_was_here = 1; 466 | break; 467 | default: 468 | if (0xc0 <= buf[3] && buf[3] < 0xf0) { 469 | /* MPEG audio or video */ 470 | if (rar_read(buf, 2, 1, mpeg->stream) != 1) 471 | return -1; 472 | len = buf[0] << 8 | buf[1]; 473 | if (len > 0 && rar_seek(mpeg->stream, len, SEEK_CUR)) 474 | return -1; 475 | } else { 476 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "unknown header 0x%02X%02X%02X%02X\n", 477 | buf[0], buf[1], buf[2], buf[3]); 478 | return -1; 479 | } 480 | } 481 | return 0; 482 | } 483 | 484 | /********************************************************************** 485 | * Packet queue 486 | **********************************************************************/ 487 | 488 | typedef struct { 489 | unsigned int pts100; 490 | off_t filepos; 491 | unsigned int size; 492 | unsigned char *data; 493 | } packet_t; 494 | 495 | typedef struct { 496 | char *id; 497 | packet_t *packets; 498 | unsigned int packets_reserve; 499 | unsigned int packets_size; 500 | unsigned int current_index; 501 | } packet_queue_t; 502 | 503 | static void packet_construct(packet_t *pkt) 504 | { 505 | pkt->pts100 = 0; 506 | pkt->filepos = 0; 507 | pkt->size = 0; 508 | pkt->data = NULL; 509 | } 510 | 511 | static void packet_destroy(packet_t *pkt) 512 | { 513 | if (pkt->data) 514 | free(pkt->data); 515 | } 516 | 517 | static void packet_queue_construct(packet_queue_t *queue) 518 | { 519 | queue->id = NULL; 520 | queue->packets = NULL; 521 | queue->packets_reserve = 0; 522 | queue->packets_size = 0; 523 | queue->current_index = 0; 524 | } 525 | 526 | static void packet_queue_destroy(packet_queue_t *queue) 527 | { 528 | if (queue->packets) { 529 | while (queue->packets_size--) 530 | packet_destroy(queue->packets + queue->packets_size); 531 | free(queue->packets); 532 | } 533 | return; 534 | } 535 | 536 | /* Make sure there is enough room for needed_size packets in the 537 | packet queue. */ 538 | static int packet_queue_ensure(packet_queue_t *queue, unsigned int needed_size) 539 | { 540 | if (queue->packets_reserve < needed_size) { 541 | if (queue->packets) { 542 | packet_t *tmp = realloc(queue->packets, 2 * queue->packets_reserve * sizeof(packet_t)); 543 | if (tmp == NULL) { 544 | mp_msg(MSGT_VOBSUB, MSGL_FATAL, "realloc failure"); 545 | return -1; 546 | } 547 | queue->packets = tmp; 548 | queue->packets_reserve *= 2; 549 | } else { 550 | queue->packets = malloc(sizeof(packet_t)); 551 | if (queue->packets == NULL) { 552 | mp_msg(MSGT_VOBSUB, MSGL_FATAL, "malloc failure"); 553 | return -1; 554 | } 555 | queue->packets_reserve = 1; 556 | } 557 | } 558 | return 0; 559 | } 560 | 561 | /* add one more packet */ 562 | static int packet_queue_grow(packet_queue_t *queue) 563 | { 564 | if (packet_queue_ensure(queue, queue->packets_size + 1) < 0) 565 | return -1; 566 | packet_construct(queue->packets + queue->packets_size); 567 | ++queue->packets_size; 568 | return 0; 569 | } 570 | 571 | /* insert a new packet, duplicating pts from the current one */ 572 | static int packet_queue_insert(packet_queue_t *queue) 573 | { 574 | packet_t *pkts; 575 | if (packet_queue_ensure(queue, queue->packets_size + 1) < 0) 576 | return -1; 577 | /* XXX packet_size does not reflect the real thing here, it will be updated a bit later */ 578 | memmove(queue->packets + queue->current_index + 2, 579 | queue->packets + queue->current_index + 1, 580 | sizeof(packet_t) * (queue->packets_size - queue->current_index - 1)); 581 | pkts = queue->packets + queue->current_index; 582 | ++queue->packets_size; 583 | ++queue->current_index; 584 | packet_construct(pkts + 1); 585 | pkts[1].pts100 = pkts[0].pts100; 586 | pkts[1].filepos = pkts[0].filepos; 587 | return 0; 588 | } 589 | 590 | /********************************************************************** 591 | * Vobsub 592 | **********************************************************************/ 593 | 594 | typedef struct { 595 | unsigned int palette[16]; 596 | int delay; 597 | unsigned int have_palette; 598 | unsigned int orig_frame_width, orig_frame_height; 599 | unsigned int origin_x, origin_y; 600 | /* index */ 601 | packet_queue_t *spu_streams; 602 | unsigned int spu_streams_size; 603 | unsigned int spu_streams_current; 604 | unsigned int spu_valid_streams_size; 605 | } vobsub_t; 606 | 607 | /* Make sure that the spu stream idx exists. */ 608 | static int vobsub_ensure_spu_stream(vobsub_t *vob, unsigned int index) 609 | { 610 | if (index >= vob->spu_streams_size) { 611 | /* This is a new stream */ 612 | if (vob->spu_streams) { 613 | packet_queue_t *tmp = realloc(vob->spu_streams, (index + 1) * sizeof(packet_queue_t)); 614 | if (tmp == NULL) { 615 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "vobsub_ensure_spu_stream: realloc failure"); 616 | return -1; 617 | } 618 | vob->spu_streams = tmp; 619 | } else { 620 | vob->spu_streams = malloc((index + 1) * sizeof(packet_queue_t)); 621 | if (vob->spu_streams == NULL) { 622 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "vobsub_ensure_spu_stream: malloc failure"); 623 | return -1; 624 | } 625 | } 626 | while (vob->spu_streams_size <= index) { 627 | packet_queue_construct(vob->spu_streams + vob->spu_streams_size); 628 | ++vob->spu_streams_size; 629 | } 630 | } 631 | return 0; 632 | } 633 | 634 | static int vobsub_add_id(vobsub_t *vob, const char *id, size_t idlen, 635 | const unsigned int index) 636 | { 637 | if (vobsub_ensure_spu_stream(vob, index) < 0) 638 | return -1; 639 | if (id && idlen) { 640 | if (vob->spu_streams[index].id) 641 | free(vob->spu_streams[index].id); 642 | vob->spu_streams[index].id = malloc(idlen + 1); 643 | if (vob->spu_streams[index].id == NULL) { 644 | mp_msg(MSGT_VOBSUB, MSGL_FATAL, "vobsub_add_id: malloc failure"); 645 | return -1; 646 | } 647 | vob->spu_streams[index].id[idlen] = 0; 648 | memcpy(vob->spu_streams[index].id, id, idlen); 649 | } 650 | vob->spu_streams_current = index; 651 | mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VOBSUB_ID=%d\n", index); 652 | if (id && idlen) 653 | mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VSID_%d_LANG=%s\n", index, vob->spu_streams[index].id); 654 | mp_msg(MSGT_VOBSUB, MSGL_V, "[vobsub] subtitle (vobsubid): %d language %s\n", 655 | index, vob->spu_streams[index].id); 656 | return 0; 657 | } 658 | 659 | static int vobsub_add_timestamp(vobsub_t *vob, off_t filepos, int ms) 660 | { 661 | packet_queue_t *queue; 662 | packet_t *pkt; 663 | if (vob->spu_streams == 0) { 664 | mp_msg(MSGT_VOBSUB, MSGL_WARN, "[vobsub] warning, binning some index entries. Check your index file\n"); 665 | return -1; 666 | } 667 | queue = vob->spu_streams + vob->spu_streams_current; 668 | if (packet_queue_grow(queue) >= 0) { 669 | pkt = queue->packets + (queue->packets_size - 1); 670 | pkt->filepos = filepos; 671 | pkt->pts100 = ms < 0 ? UINT_MAX : (unsigned int)ms * 90; 672 | return 0; 673 | } 674 | return -1; 675 | } 676 | 677 | static int vobsub_parse_id(vobsub_t *vob, const char *line) 678 | { 679 | // id: xx, index: n 680 | size_t idlen; 681 | const char *p, *q; 682 | p = line; 683 | while (isspace(*p)) 684 | ++p; 685 | q = p; 686 | while (isalpha(*q)) 687 | ++q; 688 | idlen = q - p; 689 | if (idlen == 0) 690 | return -1; 691 | ++q; 692 | while (isspace(*q)) 693 | ++q; 694 | if (strncmp("index:", q, 6)) 695 | return -1; 696 | q += 6; 697 | while (isspace(*q)) 698 | ++q; 699 | if (!isdigit(*q)) 700 | return -1; 701 | return vobsub_add_id(vob, p, idlen, atoi(q)); 702 | } 703 | 704 | static int vobsub_parse_timestamp(vobsub_t *vob, const char *line) 705 | { 706 | // timestamp: HH:MM:SS.mmm, filepos: 0nnnnnnnnn 707 | int h, m, s, ms; 708 | off_t filepos; 709 | if (sscanf(line, " %02d:%02d:%02d:%03d, filepos: %09"PRIx64"", 710 | &h, &m, &s, &ms, &filepos) != 5) 711 | return -1; 712 | return vobsub_add_timestamp(vob, filepos, vob->delay + ms + 1000 * (s + 60 * (m + 60 * h))); 713 | } 714 | 715 | static int vobsub_parse_origin(vobsub_t *vob, const char *line) 716 | { 717 | // org: X,Y 718 | unsigned x, y; 719 | 720 | if (sscanf(line, " %u,%u", &x, &y) == 2) { 721 | vob->origin_x = x; 722 | vob->origin_y = y; 723 | return 0; 724 | } 725 | return -1; 726 | } 727 | 728 | /* 729 | * The code for av_clip_uint8_c is copied from libavutil! 730 | * See libavutil/common.h. The copyright for av_clip_uint8_c is: 731 | * 732 | * copyright (c) 2006 Michael Niedermayer 733 | * 734 | * This file is part of Libav. 735 | * 736 | * Libav is free software; you can redistribute it and/or 737 | * modify it under the terms of the GNU Lesser General Public 738 | * License as published by the Free Software Foundation; either 739 | * version 2.1 of the License, or (at your option) any later version. 740 | * 741 | * Libav is distributed in the hope that it will be useful, 742 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 743 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 744 | * Lesser General Public License for more details. 745 | * 746 | * You should have received a copy of the GNU Lesser General Public 747 | * License along with Libav; if not, write to the Free Software 748 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 749 | */ 750 | 751 | /** 752 | * Clip a signed integer value into the 0-255 range. 753 | * @param a value to clip 754 | * @return clipped value 755 | */ 756 | static __attribute__((always_inline)) inline __attribute__((const)) uint8_t av_clip_uint8_c(int a) 757 | { 758 | if (a&(~0xFF)) return (-a)>>31; 759 | else return a; 760 | } 761 | #ifndef av_clip_uint8 762 | # define av_clip_uint8 av_clip_uint8_c 763 | #endif 764 | 765 | unsigned int vobsub_palette_to_yuv(unsigned int pal) 766 | { 767 | int r, g, b, y, u, v; 768 | // Palette in idx file is not rgb value, it was calculated by wrong formula. 769 | // Here's reversed formula of the one used to generate palette in idx file. 770 | r = pal >> 16 & 0xff; 771 | g = pal >> 8 & 0xff; 772 | b = pal & 0xff; 773 | y = av_clip_uint8( 0.1494 * r + 0.6061 * g + 0.2445 * b); 774 | u = av_clip_uint8( 0.6066 * r - 0.4322 * g - 0.1744 * b + 128); 775 | v = av_clip_uint8(-0.08435 * r - 0.3422 * g + 0.4266 * b + 128); 776 | y = y * 219 / 255 + 16; 777 | return y << 16 | u << 8 | v; 778 | } 779 | 780 | unsigned int vobsub_rgb_to_yuv(unsigned int rgb) 781 | { 782 | int r, g, b, y, u, v; 783 | r = rgb >> 16 & 0xff; 784 | g = rgb >> 8 & 0xff; 785 | b = rgb & 0xff; 786 | y = ( 0.299 * r + 0.587 * g + 0.114 * b) * 219 / 255 + 16.5; 787 | u = (-0.16874 * r - 0.33126 * g + 0.5 * b) * 224 / 255 + 128.5; 788 | v = ( 0.5 * r - 0.41869 * g - 0.08131 * b) * 224 / 255 + 128.5; 789 | return y << 16 | u << 8 | v; 790 | } 791 | 792 | static int vobsub_parse_delay(vobsub_t *vob, const char *line) 793 | { 794 | int h, m, s, ms; 795 | int forward = 1; 796 | if (*(line + 7) == '+') { 797 | forward = 1; 798 | line++; 799 | } else if (*(line + 7) == '-') { 800 | forward = -1; 801 | line++; 802 | } 803 | mp_msg(MSGT_SPUDEC, MSGL_V, "forward=%d", forward); 804 | h = atoi(line + 7); 805 | mp_msg(MSGT_VOBSUB, MSGL_V, "h=%d,", h); 806 | m = atoi(line + 10); 807 | mp_msg(MSGT_VOBSUB, MSGL_V, "m=%d,", m); 808 | s = atoi(line + 13); 809 | mp_msg(MSGT_VOBSUB, MSGL_V, "s=%d,", s); 810 | ms = atoi(line + 16); 811 | mp_msg(MSGT_VOBSUB, MSGL_V, "ms=%d", ms); 812 | vob->delay = (ms + 1000 * (s + 60 * (m + 60 * h))) * forward; 813 | return 0; 814 | } 815 | 816 | static int vobsub_set_lang(const char *line) 817 | { 818 | if (vobsub_id == -1) 819 | vobsub_id = atoi(line + 8); // 8 == strlen("langidx:") 820 | return 0; 821 | } 822 | 823 | static int vobsub_parse_one_line(vobsub_t *vob, rar_stream_t *fd, 824 | unsigned char **extradata, 825 | unsigned int *extradata_len) 826 | { 827 | ssize_t line_size; 828 | int res = -1; 829 | size_t line_reserve = 0; 830 | char *line = NULL; 831 | unsigned char *tmp; 832 | do { 833 | line_size = vobsub_getline(&line, &line_reserve, fd); 834 | if (line_size < 0 || line_size > 1000000 || 835 | *extradata_len+line_size > 10000000) { 836 | break; 837 | } 838 | 839 | tmp = realloc(*extradata, *extradata_len+line_size+1); 840 | if(!tmp) { 841 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "ERROR out of memory"); 842 | break; 843 | } 844 | *extradata = tmp; 845 | memcpy(*extradata+*extradata_len, line, line_size); 846 | *extradata_len += line_size; 847 | (*extradata)[*extradata_len] = 0; 848 | 849 | if (*line == 0 || *line == '\r' || *line == '\n' || *line == '#') 850 | continue; 851 | else if (strncmp("langidx:", line, 8) == 0) 852 | res = vobsub_set_lang(line); 853 | else if (strncmp("delay:", line, 6) == 0) 854 | res = vobsub_parse_delay(vob, line); 855 | else if (strncmp("id:", line, 3) == 0) 856 | res = vobsub_parse_id(vob, line + 3); 857 | else if (strncmp("org:", line, 4) == 0) 858 | res = vobsub_parse_origin(vob, line + 4); 859 | else if (strncmp("timestamp:", line, 10) == 0) 860 | res = vobsub_parse_timestamp(vob, line + 10); 861 | else { 862 | //mp_msg(MSGT_VOBSUB, MSGL_V, "vobsub: ignoring %s", line); 863 | /* 864 | size, palette, forced subs: on, and custom colors: ON, tridx are 865 | handled by spudec_parse_extradata in spudec.c 866 | */ 867 | continue; 868 | } 869 | if (res < 0) 870 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "ERROR in %s", line); 871 | break; 872 | } while (1); 873 | if (line) 874 | free(line); 875 | return res; 876 | } 877 | 878 | int vobsub_parse_ifo(void* this, const char *const name, unsigned int *palette, 879 | unsigned int *width, unsigned int *height, int force, 880 | int sid, char *langid) 881 | { 882 | vobsub_t *vob = this; 883 | int res = -1; 884 | rar_stream_t *fd = rar_open(name, "rb"); 885 | if (fd == NULL) { 886 | //if (force) 887 | //mp_msg(MSGT_VOBSUB, MSGL_WARN, "VobSub: Can't open IFO file\n"); 888 | } else { 889 | // parse IFO header 890 | unsigned char block[0x800]; 891 | const char *const ifo_magic = "DVDVIDEO-VTS"; 892 | if (rar_read(block, sizeof(block), 1, fd) != 1) { 893 | if (force) 894 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't read IFO header\n"); 895 | } else if (memcmp(block, ifo_magic, strlen(ifo_magic) + 1)) 896 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Bad magic in IFO header\n"); 897 | else { 898 | unsigned long pgci_sector = block[0xcc] << 24 | block[0xcd] << 16 899 | | block[0xce] << 8 | block[0xcf]; 900 | int standard = (block[0x200] & 0x30) >> 4; 901 | int resolution = (block[0x201] & 0x0c) >> 2; 902 | *height = standard ? 576 : 480; 903 | *width = 0; 904 | switch (resolution) { 905 | case 0x0: 906 | *width = 720; 907 | break; 908 | case 0x1: 909 | *width = 704; 910 | break; 911 | case 0x2: 912 | *width = 352; 913 | break; 914 | case 0x3: 915 | *width = 352; 916 | *height /= 2; 917 | break; 918 | default: 919 | mp_msg(MSGT_VOBSUB, MSGL_WARN, "Vobsub: Unknown resolution %d \n", resolution); 920 | } 921 | if (langid && 0 <= sid && sid < 32) { 922 | unsigned char *tmp = block + 0x256 + sid * 6 + 2; 923 | langid[0] = tmp[0]; 924 | langid[1] = tmp[1]; 925 | langid[2] = 0; 926 | } 927 | if (rar_seek(fd, pgci_sector * sizeof(block), SEEK_SET) 928 | || rar_read(block, sizeof(block), 1, fd) != 1) 929 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't read IFO PGCI\n"); 930 | else { 931 | unsigned long idx; 932 | unsigned long pgc_offset = block[0xc] << 24 | block[0xd] << 16 933 | | block[0xe] << 8 | block[0xf]; 934 | for (idx = 0; idx < 16; ++idx) { 935 | unsigned char *p = block + pgc_offset + 0xa4 + 4 * idx; 936 | palette[idx] = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; 937 | } 938 | if (vob) 939 | vob->have_palette = 1; 940 | res = 0; 941 | } 942 | } 943 | rar_close(fd); 944 | } 945 | return res; 946 | } 947 | 948 | void *vobsub_open(const char *const name, const char *const ifo, 949 | const int force, unsigned int y_threshold, void** spu) 950 | { 951 | unsigned char *extradata = NULL; 952 | unsigned int extradata_len = 0; 953 | vobsub_t *vob = calloc(1, sizeof(vobsub_t)); 954 | if (spu) 955 | *spu = NULL; 956 | if (vobsubid == -2) 957 | vobsubid = vobsub_id; 958 | if (vob) { 959 | char *buf; 960 | buf = malloc(strlen(name) + 5); 961 | if (buf) { 962 | rar_stream_t *fd; 963 | mpeg_t *mpg; 964 | /* read in the info file */ 965 | if (!ifo) { 966 | strcpy(buf, name); 967 | strcat(buf, ".ifo"); 968 | vobsub_parse_ifo(vob, buf, vob->palette, &vob->orig_frame_width, &vob->orig_frame_height, force, -1, NULL); 969 | } else 970 | vobsub_parse_ifo(vob, ifo, vob->palette, &vob->orig_frame_width, &vob->orig_frame_height, force, -1, NULL); 971 | /* read in the index */ 972 | strcpy(buf, name); 973 | strcat(buf, ".idx"); 974 | fd = rar_open(buf, "rb"); 975 | if (fd == NULL) { 976 | if (force) 977 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't open IDX file\n"); 978 | else { 979 | free(buf); 980 | free(vob); 981 | return NULL; 982 | } 983 | } else { 984 | while (vobsub_parse_one_line(vob, fd, &extradata, &extradata_len) >= 0) 985 | /* NOOP */ ; 986 | rar_close(fd); 987 | } 988 | if (spu) 989 | *spu = spudec_new_scaled(vob->palette, vob->orig_frame_width, vob->orig_frame_height, extradata, extradata_len, y_threshold); 990 | if (extradata) 991 | free(extradata); 992 | 993 | /* read the indexed mpeg_stream */ 994 | strcpy(buf, name); 995 | strcat(buf, ".sub"); 996 | mpg = mpeg_open(buf); 997 | if (mpg == NULL) { 998 | if (force) 999 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't open SUB file\n"); 1000 | else { 1001 | free(buf); 1002 | free(vob); 1003 | return NULL; 1004 | } 1005 | } else { 1006 | long last_pts_diff = 0; 1007 | while (!mpeg_eof(mpg)) { 1008 | off_t pos = mpeg_tell(mpg); 1009 | if (mpeg_run(mpg) < 0) { 1010 | if (!mpeg_eof(mpg)) 1011 | mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: mpeg_run error\n"); 1012 | break; 1013 | } 1014 | if (mpg->packet_size) { 1015 | if ((mpg->aid & 0xe0) == 0x20) { 1016 | unsigned int sid = mpg->aid & 0x1f; 1017 | if (vobsub_ensure_spu_stream(vob, sid) >= 0) { 1018 | packet_queue_t *queue = vob->spu_streams + sid; 1019 | /* get the packet to fill */ 1020 | if (queue->packets_size == 0 && packet_queue_grow(queue) < 0) 1021 | abort(); 1022 | while (queue->current_index + 1 < queue->packets_size 1023 | && queue->packets[queue->current_index + 1].filepos <= pos) 1024 | ++queue->current_index; 1025 | if (queue->current_index < queue->packets_size) { 1026 | packet_t *pkt; 1027 | if (queue->packets[queue->current_index].data) { 1028 | /* insert a new packet and fix the PTS ! */ 1029 | packet_queue_insert(queue); 1030 | queue->packets[queue->current_index].pts100 = 1031 | mpg->pts + last_pts_diff; 1032 | } 1033 | pkt = queue->packets + queue->current_index; 1034 | if (pkt->pts100 != UINT_MAX) { 1035 | if (queue->packets_size > 1) 1036 | last_pts_diff = pkt->pts100 - mpg->pts; 1037 | else 1038 | pkt->pts100 = mpg->pts; 1039 | if (mpg->merge && queue->current_index > 0) { 1040 | packet_t *last = &queue->packets[queue->current_index - 1]; 1041 | pkt->pts100 = last->pts100; 1042 | } 1043 | mpg->merge = 0; 1044 | /* FIXME: should not use mpg_sub internal informations, make a copy */ 1045 | pkt->data = mpg->packet; 1046 | pkt->size = mpg->packet_size; 1047 | mpg->packet = NULL; 1048 | mpg->packet_reserve = 0; 1049 | mpg->packet_size = 0; 1050 | } 1051 | } 1052 | } else 1053 | mp_msg(MSGT_VOBSUB, MSGL_WARN, "don't know what to do with subtitle #%u\n", sid); 1054 | } 1055 | } 1056 | } 1057 | vob->spu_streams_current = vob->spu_streams_size; 1058 | while (vob->spu_streams_current-- > 0) { 1059 | vob->spu_streams[vob->spu_streams_current].current_index = 0; 1060 | if (vobsubid == vob->spu_streams_current || 1061 | vob->spu_streams[vob->spu_streams_current].packets_size > 0) 1062 | ++vob->spu_valid_streams_size; 1063 | } 1064 | mpeg_free(mpg); 1065 | } 1066 | free(buf); 1067 | } 1068 | } 1069 | return vob; 1070 | } 1071 | 1072 | void vobsub_close(void *this) 1073 | { 1074 | vobsub_t *vob = this; 1075 | if (vob->spu_streams) { 1076 | while (vob->spu_streams_size--) 1077 | packet_queue_destroy(vob->spu_streams + vob->spu_streams_size); 1078 | free(vob->spu_streams); 1079 | } 1080 | free(vob); 1081 | } 1082 | 1083 | unsigned int vobsub_get_indexes_count(void *vobhandle) 1084 | { 1085 | vobsub_t *vob = vobhandle; 1086 | return vob->spu_valid_streams_size; 1087 | } 1088 | 1089 | char *vobsub_get_id(void *vobhandle, unsigned int index) 1090 | { 1091 | vobsub_t *vob = vobhandle; 1092 | return (index < vob->spu_streams_size) ? vob->spu_streams[index].id : NULL; 1093 | } 1094 | 1095 | int vobsub_get_id_by_index(void *vobhandle, unsigned int index) 1096 | { 1097 | vobsub_t *vob = vobhandle; 1098 | int i, j; 1099 | if (vob == NULL) 1100 | return -1; 1101 | for (i = 0, j = 0; i < vob->spu_streams_size; ++i) 1102 | if (i == vobsubid || vob->spu_streams[i].packets_size > 0) { 1103 | if (j == index) 1104 | return i; 1105 | ++j; 1106 | } 1107 | return -1; 1108 | } 1109 | 1110 | int vobsub_get_index_by_id(void *vobhandle, int id) 1111 | { 1112 | vobsub_t *vob = vobhandle; 1113 | int i, j; 1114 | if (vob == NULL || id < 0 || id >= vob->spu_streams_size) 1115 | return -1; 1116 | if (id != vobsubid && !vob->spu_streams[id].packets_size) 1117 | return -1; 1118 | for (i = 0, j = 0; i < id; ++i) 1119 | if (i == vobsubid || vob->spu_streams[i].packets_size > 0) 1120 | ++j; 1121 | return j; 1122 | } 1123 | 1124 | int vobsub_set_from_lang(void *vobhandle, char const *lang) 1125 | { 1126 | int i; 1127 | vobsub_t *vob= vobhandle; 1128 | while (lang && strlen(lang) >= 2) { 1129 | for (i = 0; i < vob->spu_streams_size; i++) 1130 | if (vob->spu_streams[i].id) 1131 | if ((strncmp(vob->spu_streams[i].id, lang, 2) == 0)) { 1132 | vobsub_id = i; 1133 | mp_msg(MSGT_VOBSUB, MSGL_INFO, "Selected VOBSUB language: %d language: %s\n", i, vob->spu_streams[i].id); 1134 | return 0; 1135 | } 1136 | lang+=2;while (lang[0]==',' || lang[0]==' ') ++lang; 1137 | } 1138 | mp_msg(MSGT_VOBSUB, MSGL_WARN, "No matching VOBSUB language found!\n"); 1139 | return -1; 1140 | } 1141 | 1142 | /// make sure we seek to the first packet of packets having same pts values. 1143 | static void vobsub_queue_reseek(packet_queue_t *queue, unsigned int pts100) 1144 | { 1145 | int reseek_count = 0; 1146 | unsigned int lastpts = 0; 1147 | 1148 | if (queue->current_index > 0 1149 | && (queue->packets[queue->current_index].pts100 == UINT_MAX 1150 | || queue->packets[queue->current_index].pts100 > pts100)) { 1151 | // possible pts seek previous, try to check it. 1152 | int i = 1; 1153 | while (queue->current_index >= i 1154 | && queue->packets[queue->current_index-i].pts100 == UINT_MAX) 1155 | ++i; 1156 | if (queue->current_index >= i 1157 | && queue->packets[queue->current_index-i].pts100 > pts100) 1158 | // pts seek previous confirmed, reseek from beginning 1159 | queue->current_index = 0; 1160 | } 1161 | while (queue->current_index < queue->packets_size 1162 | && queue->packets[queue->current_index].pts100 <= pts100) { 1163 | lastpts = queue->packets[queue->current_index].pts100; 1164 | ++queue->current_index; 1165 | ++reseek_count; 1166 | } 1167 | while (reseek_count-- && --queue->current_index) { 1168 | if (queue->packets[queue->current_index-1].pts100 != UINT_MAX && 1169 | queue->packets[queue->current_index-1].pts100 != lastpts) 1170 | break; 1171 | } 1172 | } 1173 | 1174 | int vobsub_get_packet(void *vobhandle, float pts, void** data, int* timestamp) 1175 | { 1176 | vobsub_t *vob = vobhandle; 1177 | unsigned int pts100 = 90000 * pts; 1178 | if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { 1179 | packet_queue_t *queue = vob->spu_streams + vobsub_id; 1180 | 1181 | vobsub_queue_reseek(queue, pts100); 1182 | 1183 | while (queue->current_index < queue->packets_size) { 1184 | packet_t *pkt = queue->packets + queue->current_index; 1185 | if (pkt->pts100 != UINT_MAX) 1186 | if (pkt->pts100 <= pts100) { 1187 | ++queue->current_index; 1188 | *data = pkt->data; 1189 | *timestamp = pkt->pts100; 1190 | return pkt->size; 1191 | } else 1192 | break; 1193 | else 1194 | ++queue->current_index; 1195 | } 1196 | } 1197 | return -1; 1198 | } 1199 | 1200 | int vobsub_get_next_packet(void *vobhandle, void** data, int* timestamp) 1201 | { 1202 | vobsub_t *vob = vobhandle; 1203 | if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { 1204 | packet_queue_t *queue = vob->spu_streams + vobsub_id; 1205 | if (queue->current_index < queue->packets_size) { 1206 | packet_t *pkt = queue->packets + queue->current_index; 1207 | ++queue->current_index; 1208 | *data = pkt->data; 1209 | *timestamp = pkt->pts100; 1210 | return pkt->size; 1211 | } 1212 | } 1213 | return -1; 1214 | } 1215 | 1216 | void vobsub_seek(void * vobhandle, float pts) 1217 | { 1218 | vobsub_t * vob = vobhandle; 1219 | packet_queue_t * queue; 1220 | int seek_pts100 = pts * 90000; 1221 | 1222 | if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { 1223 | /* do not seek if we don't know the id */ 1224 | if (vobsub_get_id(vob, vobsub_id) == NULL) 1225 | return; 1226 | queue = vob->spu_streams + vobsub_id; 1227 | queue->current_index = 0; 1228 | vobsub_queue_reseek(queue, seek_pts100); 1229 | } 1230 | } 1231 | 1232 | void vobsub_reset(void *vobhandle) 1233 | { 1234 | vobsub_t *vob = vobhandle; 1235 | if (vob->spu_streams) { 1236 | unsigned int n = vob->spu_streams_size; 1237 | while (n-- > 0) 1238 | vob->spu_streams[n].current_index = 0; 1239 | } 1240 | } 1241 | 1242 | #if 0 // R: no output needed 1243 | /********************************************************************** 1244 | * Vobsub output 1245 | **********************************************************************/ 1246 | 1247 | typedef struct { 1248 | FILE *fsub; 1249 | FILE *fidx; 1250 | unsigned int aid; 1251 | } vobsub_out_t; 1252 | 1253 | static void create_idx(vobsub_out_t *me, const unsigned int *palette, 1254 | unsigned int orig_width, unsigned int orig_height) 1255 | { 1256 | int i; 1257 | fprintf(me->fidx, 1258 | "# VobSub index file, v7 (do not modify this line!)\n" 1259 | "#\n" 1260 | "# Generated by %s\n" 1261 | "# See for more information about MPlayer\n" 1262 | "# See for more information about Vobsub\n" 1263 | "#\n" 1264 | "size: %ux%u\n", 1265 | mplayer_version, orig_width, orig_height); 1266 | if (palette) { 1267 | fputs("palette:", me->fidx); 1268 | for (i = 0; i < 16; ++i) { 1269 | const double y = palette[i] >> 16 & 0xff, 1270 | u = (palette[i] >> 8 & 0xff) - 128.0, 1271 | v = (palette[i] & 0xff) - 128.0; 1272 | if (i) 1273 | putc(',', me->fidx); 1274 | fprintf(me->fidx, " %02x%02x%02x", 1275 | av_clip_uint8(y + 1.4022 * u), 1276 | av_clip_uint8(y - 0.3456 * u - 0.7145 * v), 1277 | av_clip_uint8(y + 1.7710 * v)); 1278 | } 1279 | putc('\n', me->fidx); 1280 | } 1281 | 1282 | fprintf(me->fidx, "# ON: displays only forced subtitles, OFF: shows everything\n" 1283 | "forced subs: OFF\n"); 1284 | } 1285 | 1286 | void *vobsub_out_open(const char *basename, const unsigned int *palette, 1287 | unsigned int orig_width, unsigned int orig_height, 1288 | const char *id, unsigned int index) 1289 | { 1290 | vobsub_out_t *result = NULL; 1291 | char *filename; 1292 | filename = malloc(strlen(basename) + 5); 1293 | if (filename) { 1294 | result = malloc(sizeof(vobsub_out_t)); 1295 | if (result) { 1296 | result->aid = index; 1297 | strcpy(filename, basename); 1298 | strcat(filename, ".sub"); 1299 | result->fsub = fopen(filename, "ab"); 1300 | if (result->fsub == NULL) 1301 | perror("Error: vobsub_out_open subtitle file open failed"); 1302 | strcpy(filename, basename); 1303 | strcat(filename, ".idx"); 1304 | result->fidx = fopen(filename, "ab"); 1305 | if (result->fidx) { 1306 | if (ftell(result->fidx) == 0) { 1307 | create_idx(result, palette, orig_width, orig_height); 1308 | /* Make the selected language the default language */ 1309 | fprintf(result->fidx, "\n# Language index in use\nlangidx: %u\n", index); 1310 | } 1311 | fprintf(result->fidx, "\nid: %s, index: %u\n", id ? id : "xx", index); 1312 | /* So that we can check the file now */ 1313 | fflush(result->fidx); 1314 | } else 1315 | perror("Error: vobsub_out_open index file open failed"); 1316 | free(filename); 1317 | } 1318 | } 1319 | return result; 1320 | } 1321 | 1322 | void vobsub_out_close(void *me) 1323 | { 1324 | vobsub_out_t *vob = me; 1325 | if (vob->fidx) 1326 | fclose(vob->fidx); 1327 | if (vob->fsub) 1328 | fclose(vob->fsub); 1329 | free(vob); 1330 | } 1331 | 1332 | void vobsub_out_output(void *me, const unsigned char *packet, 1333 | int len, double pts) 1334 | { 1335 | static double last_pts; 1336 | static int last_pts_set = 0; 1337 | vobsub_out_t *vob = me; 1338 | if (vob->fsub) { 1339 | /* Windows' Vobsub require that every packet is exactly 2kB long */ 1340 | unsigned char buffer[2048]; 1341 | unsigned char *p; 1342 | int remain = 2048; 1343 | /* Do not output twice a line with the same timestamp, this 1344 | breaks Windows' Vobsub */ 1345 | if (vob->fidx && (!last_pts_set || last_pts != pts)) { 1346 | static unsigned int last_h = 9999, last_m = 9999, last_s = 9999, last_ms = 9999; 1347 | unsigned int h, m, ms; 1348 | double s; 1349 | s = pts; 1350 | h = s / 3600; 1351 | s -= h * 3600; 1352 | m = s / 60; 1353 | s -= m * 60; 1354 | ms = (s - (unsigned int) s) * 1000; 1355 | if (ms >= 1000) /* prevent overflows or bad float stuff */ 1356 | ms = 0; 1357 | if (h != last_h || m != last_m || (unsigned int) s != last_s || ms != last_ms) { 1358 | fprintf(vob->fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: %09lx\n", 1359 | h, m, (unsigned int) s, ms, ftell(vob->fsub)); 1360 | last_h = h; 1361 | last_m = m; 1362 | last_s = (unsigned int) s; 1363 | last_ms = ms; 1364 | } 1365 | } 1366 | last_pts = pts; 1367 | last_pts_set = 1; 1368 | 1369 | /* Packet start code: Windows' Vobsub needs this */ 1370 | p = buffer; 1371 | *p++ = 0; /* 0x00 */ 1372 | *p++ = 0; 1373 | *p++ = 1; 1374 | *p++ = 0xba; 1375 | *p++ = 0x40; 1376 | memset(p, 0, 9); 1377 | p += 9; 1378 | { /* Packet */ 1379 | static unsigned char last_pts[5] = { 0, 0, 0, 0, 0}; 1380 | unsigned char now_pts[5]; 1381 | int pts_len, pad_len, datalen = len; 1382 | pts *= 90000; 1383 | now_pts[0] = 0x21 | (((unsigned long)pts >> 29) & 0x0e); 1384 | now_pts[1] = ((unsigned long)pts >> 22) & 0xff; 1385 | now_pts[2] = 0x01 | (((unsigned long)pts >> 14) & 0xfe); 1386 | now_pts[3] = ((unsigned long)pts >> 7) & 0xff; 1387 | now_pts[4] = 0x01 | (((unsigned long)pts << 1) & 0xfe); 1388 | pts_len = memcmp(last_pts, now_pts, sizeof(now_pts)) ? sizeof(now_pts) : 0; 1389 | memcpy(last_pts, now_pts, sizeof(now_pts)); 1390 | 1391 | datalen += 3; /* Version, PTS_flags, pts_len */ 1392 | datalen += pts_len; 1393 | datalen += 1; /* AID */ 1394 | pad_len = 2048 - (p - buffer) - 4 /* MPEG ID */ - 2 /* payload len */ - datalen; 1395 | /* XXX - Go figure what should go here! In any case the 1396 | packet has to be completely filled. If I can fill it 1397 | with padding (0x000001be) latter I'll do that. But if 1398 | there is only room for 6 bytes then I can not write a 1399 | padding packet. So I add some padding in the PTS 1400 | field. This looks like a dirty kludge. Oh well... */ 1401 | if (pad_len < 0) { 1402 | /* Packet is too big. Let's try omitting the PTS field */ 1403 | datalen -= pts_len; 1404 | pts_len = 0; 1405 | pad_len = 0; 1406 | } else if (pad_len > 6) 1407 | pad_len = 0; 1408 | datalen += pad_len; 1409 | 1410 | *p++ = 0; /* 0x0e */ 1411 | *p++ = 0; 1412 | *p++ = 1; 1413 | *p++ = 0xbd; 1414 | 1415 | *p++ = (datalen >> 8) & 0xff; /* length of payload */ 1416 | *p++ = datalen & 0xff; 1417 | *p++ = 0x80; /* System-2 (.VOB) stream */ 1418 | *p++ = pts_len ? 0x80 : 0x00; /* pts_flags */ 1419 | *p++ = pts_len + pad_len; 1420 | memcpy(p, now_pts, pts_len); 1421 | p += pts_len; 1422 | memset(p, 0, pad_len); 1423 | p += pad_len; 1424 | } 1425 | *p++ = 0x20 | vob->aid; /* aid */ 1426 | if (fwrite(buffer, p - buffer, 1, vob->fsub) != 1 1427 | || fwrite(packet, len, 1, vob->fsub) != 1) 1428 | perror("ERROR: vobsub write failed"); 1429 | else 1430 | remain -= p - buffer + len; 1431 | 1432 | /* Padding */ 1433 | if (remain >= 6) { 1434 | p = buffer; 1435 | *p++ = 0x00; 1436 | *p++ = 0x00; 1437 | *p++ = 0x01; 1438 | *p++ = 0xbe; 1439 | *p++ = (remain - 6) >> 8; 1440 | *p++ = (remain - 6) & 0xff; 1441 | /* for better compression, blank this */ 1442 | memset(buffer + 6, 0, remain - (p - buffer)); 1443 | if (fwrite(buffer, remain, 1, vob->fsub) != 1) 1444 | perror("ERROR: vobsub padding write failed"); 1445 | } else if (remain > 0) { 1446 | /* I don't know what to output. But anyway the block 1447 | needs to be 2KB big */ 1448 | memset(buffer, 0, remain); 1449 | if (fwrite(buffer, remain, 1, vob->fsub) != 1) 1450 | perror("ERROR: vobsub blank padding write failed"); 1451 | } else if (remain < 0) 1452 | fprintf(stderr, 1453 | "\nERROR: wrong thing happened...\n" 1454 | " I wrote a %i data bytes spu packet and that's too long\n", len); 1455 | } 1456 | } 1457 | #endif 1458 | -------------------------------------------------------------------------------- /mplayer/vobsub.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MPlayer. 3 | * 4 | * MPlayer is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MPlayer is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with MPlayer; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef MPLAYER_VOBSUB_H 20 | #define MPLAYER_VOBSUB_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | extern int vobsub_id; // R: moved from mpcommon.h 27 | 28 | void *vobsub_open(const char *subname, const char *const ifo, const int force, unsigned int y_threshold, void** spu); 29 | void vobsub_reset(void *vob); 30 | int vobsub_parse_ifo(void* self, const char *const name, unsigned int *palette, unsigned int *width, unsigned int *height, int force, int sid, char *langid); 31 | int vobsub_get_packet(void *vobhandle, float pts,void** data, int* timestamp); 32 | int vobsub_get_next_packet(void *vobhandle, void** data, int* timestamp); 33 | void vobsub_close(void *self); 34 | unsigned int vobsub_get_indexes_count(void * /* vobhandle */); 35 | char *vobsub_get_id(void * /* vobhandle */, unsigned int /* index */); 36 | 37 | /// Get vobsub id by its index in the valid streams. 38 | int vobsub_get_id_by_index(void *vobhandle, unsigned int index); 39 | /// Get index in the valid streams by vobsub id. 40 | int vobsub_get_index_by_id(void *vobhandle, int id); 41 | 42 | /// Convert palette value in idx file to yuv. 43 | unsigned int vobsub_palette_to_yuv(unsigned int pal); 44 | /// Convert rgb value to yuv. 45 | unsigned int vobsub_rgb_to_yuv(unsigned int rgb); 46 | 47 | #if 0 // R: no output needed 48 | void *vobsub_out_open(const char *basename, const unsigned int *palette, unsigned int orig_width, unsigned int orig_height, const char *id, unsigned int index); 49 | void vobsub_out_output(void *me, const unsigned char *packet, int len, double pts); 50 | void vobsub_out_close(void *me); 51 | #endif 52 | int vobsub_set_from_lang(void *vobhandle, char const *lang); // R: changed lang from unsigned char* 53 | void vobsub_seek(void * vobhandle, float pts); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif /* MPLAYER_VOBSUB_H */ 60 | -------------------------------------------------------------------------------- /packaging/vobsub2srt-9999.ebuild: -------------------------------------------------------------------------------- 1 | # -*- mode:sh; -*- 2 | 3 | # See https://github.com/ruediger/VobSub2SRT/issues/13 4 | 5 | # Copyright 1999-2013 Gentoo Foundation 6 | # Distributed under the terms of the GNU General Public License v2 7 | 8 | EAPI="4" 9 | 10 | EGIT_REPO_URI="git://github.com/ruediger/VobSub2SRT.git" 11 | 12 | inherit cmake-utils git-2 13 | 14 | IUSE="" 15 | 16 | DESCRIPTION="Converts image subtitles created by VobSub (.sub/.idx) to .srt textual subtitles using tesseract OCR engine" 17 | HOMEPAGE="https://github.com/ruediger/VobSub2SRT" 18 | 19 | LICENSE="GPL-3" 20 | SLOT="0" 21 | KEYWORDS="~amd64 ~x86" 22 | 23 | RDEPEND=">=app-text/tesseract-2.04-r1 24 | >=virtual/ffmpeg-0.6.90" 25 | DEPEND="${RDEPEND}" 26 | -------------------------------------------------------------------------------- /packaging/vobsub2srt.rb: -------------------------------------------------------------------------------- 1 | # Homebrew Formula for VobSub2SRT 2 | # Usage: brew install https://github.com/ruediger/VobSub2SRT/raw/master/vobsub2srt.rb 3 | 4 | require 'formula' 5 | 6 | class Vobsub2srt < Formula 7 | head 'git://github.com/ruediger/VobSub2SRT.git', :using => :git 8 | homepage 'https://github.com/ruediger/VobSub2SRT' 9 | 10 | depends_on 'cmake' 11 | depends_on 'tesseract' 12 | depends_on 'ffmpeg' 13 | 14 | def install 15 | mkdir "build" do 16 | system "cmake", "..", *std_cmake_args 17 | system "make", "install" 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /packaging/vobsub2srt.spec: -------------------------------------------------------------------------------- 1 | %global commit 1746781ee4a98d92d70ba7198246c58285296437 2 | %global shortcommit %(c=%{commit}; echo ${c:0:7}) 3 | %global commitdate 20130216 4 | %global gittag %{commitdate}git%{shortcommit} 5 | 6 | Name: vobsub2srt 7 | Version: 1.0 8 | Release: 1%{?dist}.%{gittag} 9 | Summary: VobSub2SRT .sub/.idx to .srt subtitle converter 10 | 11 | Group: Applications/Multimedia 12 | License: GPLv3+ 13 | URL: https://github.com/ruediger/VobSub2SRT 14 | Source0: https://github.com/ruediger/VobSub2SRT/archive/%{commit}/%{name}-%{version}-%{shortcommit}.tar.gz 15 | 16 | BuildRequires: cmake 17 | BuildRequires: tesseract-devel 18 | BuildRequires: libtiff-devel 19 | 20 | %description 21 | VobSub2SRT is a simple command line program to convert .idx / .sub subtitles 22 | into .srt text subtitles by using OCR. It is based on code from the MPlayer 23 | project. 24 | 25 | %prep 26 | %setup -qn VobSub2SRT-%{commit} 27 | 28 | %build 29 | mkdir -p %{_target_platform} 30 | pushd %{_target_platform} 31 | %{cmake} \ 32 | -D INSTALL_DOC_DIR=%{_docdir}/%{name}-%{version} \ 33 | .. 34 | popd 35 | 36 | make %{?_smp_mflags} -C %{_target_platform} 37 | 38 | %install 39 | make install DESTDIR=%{buildroot} -C %{_target_platform} 40 | mv %{buildroot}/%{_docdir}/%{name}/copyright . 41 | mv %{buildroot}/%{_docdir}/%{name}/README . 42 | 43 | 44 | %files 45 | %doc README copyright 46 | %{_mandir}/man1/vobsub2srt.1.gz 47 | %{_bindir}/vobsub2srt 48 | 49 | 50 | %changelog 51 | * Sat Feb 16 2013 Vinzenz Feenstra - 1.0-1.20130216git1746781 52 | - Initial package 53 | 54 | -------------------------------------------------------------------------------- /packaging/vobsub2srt.spec.rst: -------------------------------------------------------------------------------- 1 | pushd ~/rpmbuild/SOURCE 2 | wget https://github.com/ruediger/VobSub2SRT/archive/1746781ee4a98d92d70ba7198246c58285296437/vobsub2srt-0.1-1746781.tar.gz 3 | popd 4 | rpmbuild -ba vobsub2srt.spec 5 | yum install -y `find ~/rpmbuild/RPMS -name vobsub2srt-0.1.*` 6 | 7 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(${vobsub2srt_SOURCE_DIR}/mplayer) 2 | 3 | link_directories(${Libavutil_LIBRARY_DIRS}) 4 | include_directories(${Libavutil_INCLUDE_DIRS}) 5 | include_directories(${Tesseract_INCLUDE_DIR}) 6 | 7 | set(vobsub2srt_sources 8 | vobsub2srt.c++ 9 | langcodes.h++ 10 | langcodes.c++ 11 | cmd_options.h++ 12 | cmd_options.c++) 13 | 14 | add_executable(vobsub2srt ${vobsub2srt_sources}) 15 | if(BUILD_STATIC) 16 | set_target_properties(vobsub2srt PROPERTIES 17 | LINK_SEARCH_END_STATIC ON 18 | LINK_FLAGS -static) 19 | endif() 20 | target_link_libraries(vobsub2srt mplayer ${Libavutil_LIBRARIES} ${Tesseract_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) 21 | 22 | install(TARGETS vobsub2srt RUNTIME DESTINATION ${INSTALL_EXECUTABLES_PATH}) 23 | -------------------------------------------------------------------------------- /src/cmd_options.c++: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of vobsub2srt 3 | * 4 | * Copyright (C) 2010-2016 Rüdiger Sonderfeld 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include "cmd_options.h++" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | using namespace std; 27 | 28 | namespace { 29 | struct option { 30 | enum arg_type { Bool, String, Int } type; 31 | union { 32 | bool *flag; 33 | std::string *str; 34 | int *i; 35 | } ref; 36 | char const *name; 37 | char const *description; 38 | char short_name; 39 | 40 | template 41 | option(char const *name, arg_type type, T &r, char const *description, char short_name) 42 | : type(type), name(name), description(description), short_name(short_name) 43 | { 44 | switch(type) { 45 | case Bool: 46 | ref.flag = reinterpret_cast(&r); 47 | break; 48 | case String: 49 | ref.str = reinterpret_cast(&r); 50 | break; 51 | case Int: 52 | ref.i = reinterpret_cast(&r); 53 | break; 54 | } 55 | } 56 | }; 57 | 58 | struct unnamed { 59 | std::string *str; 60 | char const *name; 61 | char const *description; 62 | unnamed(std::string &s, char const *name, char const *description) 63 | : str(&s), name(name), description(description) 64 | { } 65 | }; 66 | 67 | } 68 | 69 | struct cmd_options::impl { 70 | std::vector