diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml new file mode 100644 index 0000000..a4cd9e6 --- /dev/null +++ b/.github/workflows/c-cpp.yml @@ -0,0 +1,27 @@ +name: C/C++ CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + - name: update-apt + run: sudo apt update + - name: install-deps + run: sudo apt install libpng-dev libtesseract-dev tesseract-ocr-eng libtiff5-dev g++ gcc cmake -y + - name: configure + run: ./configure + - name: make + run: make + - name: make install + run: sudo make install + - name: vobsub2srt-runtest + run: vobsub2srt --help diff --git a/CMakeLists.txt b/CMakeLists.txt index d1954cb..7a871b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,12 @@ +cmake_minimum_required(VERSION 3.10) project(vobsub2srt) -cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR) - set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules) if(NOT CMAKE_BUILD_TYPE) set( CMAKE_BUILD_TYPE - Debug + Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." @@ -53,17 +52,20 @@ include(CheckCXXCompilerFlag) include(CheckCXXSourceCompiles) include(CheckCXXSourceRuns) -set(CMAKE_C_FLAGS "-std=gnu99") -set(CMAKE_CXX_FLAGS "-ansi -pedantic -Wall -Wextra -Wno-long-long") +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_FLAGS "-Wall -Wextra") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "-pedantic -Wall -Wextra") -set(CMAKE_CXX_FLAGS_RELEASE "-O3 -mtune=native -march=native -DNDEBUG -fomit-frame-pointer -ffast-math") # TODO -Ofast GCC 4.6 +set(CMAKE_CXX_FLAGS_RELEASE "-O2 -march=native -DNDEBUG") set(CMAKE_C_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) -set(CMAKE_CXX_FLAGS_DEBUG "-g3 -DDEBUG") +set(CMAKE_CXX_FLAGS_DEBUG "-g3 -DDEBUG -fsanitize=address,undefined") set(CMAKE_C_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) -# TODO RelWithDebInfo MinSizeRel? maybe move -march=native -ffast-math etc. to a different build type +find_package(Leptonica REQUIRED) find_package(Threads) -find_package(Tesseract) +find_package(Tesseract REQUIRED) +find_package(PNG REQUIRED) add_subdirectory(mplayer) add_subdirectory(src) @@ -121,10 +123,10 @@ else() set(CPACK_GENERATOR "DEB") set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") set(CPACK_PACKAGE_VERSION "${VOBSUB2SRT_VERSION}") - set(CPACK_PACKAGE_CONTACT "Rüdiger Sonderfeld ") - set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/ruediger/VobSub2SRT") + set(CPACK_PACKAGE_CONTACT "Christopher Ogloff ") + set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/csingleplus/VobSub2SRT") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Converts VobSub subtitles (.idx/.srt format) into .srt subtitles.") - 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.") + 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.\nTesseract is used as OCR software.") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/debian/copyright") set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.org") @@ -144,7 +146,7 @@ else() include(CPack) if(ENABLE_PPA) - set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "any") # can be build on any system + set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "any") # can be built on any system include(UploadPPA) endif() endif() diff --git a/CMakeModules/FindLeptonica.cmake b/CMakeModules/FindLeptonica.cmake new file mode 100644 index 0000000..286185a --- /dev/null +++ b/CMakeModules/FindLeptonica.cmake @@ -0,0 +1,26 @@ +find_path(Leptonica_INCLUDE_DIR + NAMES leptonica/allheaders.h allheaders.h + HINTS + /usr/include + /usr/local/include +) + +find_library(Leptonica_LIBRARY + NAMES leptonica lept + HINTS + /usr/lib + /usr/lib/x86_64-linux-gnu + /usr/local/lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Leptonica + REQUIRED_VARS Leptonica_LIBRARY Leptonica_INCLUDE_DIR +) + +if(Leptonica_FOUND) + set(Leptonica_LIBRARIES ${Leptonica_LIBRARY}) + set(Leptonica_INCLUDE_DIRS ${Leptonica_INCLUDE_DIR}) +endif() + +mark_as_advanced(Leptonica_INCLUDE_DIR Leptonica_LIBRARY) \ No newline at end of file diff --git a/CMakeModules/FindTesseract.cmake b/CMakeModules/FindTesseract.cmake index 4b15d74..d9a902d 100644 --- a/CMakeModules/FindTesseract.cmake +++ b/CMakeModules/FindTesseract.cmake @@ -44,17 +44,6 @@ if(TESSERACT_DATA_PATH) endif() set(CMAKE_REQUIRED_INCLUDES ${Tesseract_INCLUDE_DIR}) -check_cxx_source_compiles( - "#include \"tesseract/baseapi.h\" - using namespace tesseract; - int main() { - }" - TESSERACT_NAMESPACE) -if(TESSERACT_NAMESPACE) - add_definitions("-DCONFIG_TESSERACT_NAMESPACE") -else() - message(WARNING "You are using an old Tesseract version. Support for Tesseract 2 is deprecated and will be removed in the future!") -endif() list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES ${Tesseract_INCLUDE_DIR}) if(BUILD_STATIC) diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..f4a604e --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,21 @@ +Most code is from the MPlayer project. +- Chris Ogloff Mar. 2026: added memory safety, + modern Tesseract calls, validated with Valgrind, separated MPlayer verbosity + from displaying realtime subtitle decoding, ensured compatibility across Linux distributions. + Apr. 2026: Scaling code implemented (though it needs preprocessing). + Jun. 2026: PNG writing implemented. +- Ethan Dye https://github.com/ecdye/VobSub2SRT + Image inversion code, resulting in cleaner and quicker output. +- Armin Häberling wrote a patch to fix an issue with + multiple instances of the same subtitle in result file (21af426) +- James Harris wrote the formula for Homebrew (54f311d6) +- Leo Koppelkamm reported and fixed issue #5 and problems with long filenames + (b903074c, 36ec8da, d3602d6) +- Till Korten wrote the ebuild script (#13) +- Andreasf fixed missing libavutil include path (3a175eb, #15) +- Michal Gawlik fixed the overlapping issue (5b2ccabc55f, #29, #32) +- "bit" made sure no trailing whitespace are written to the SRT (3a59dc278abc2, #38) +- Baudouin Raoult for various fixes (028f742, #44, b722a03, #42, 7293ac2, #40) +- Justyn Butler added the y-threshold support (f873761, #43) +- James Laird-Wah added min-width/height support and fixed other issues (41c6844, #48, #46) +- Filirom1 fixed a minor issue (4ed58c2, #49) diff --git a/COPYING b/COPYING index 94a9ed0..94a0453 100644 --- a/COPYING +++ b/COPYING @@ -619,56 +619,3 @@ Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/README.org b/README.org index 745317f..582b151 100644 --- a/README.org +++ b/README.org @@ -1,28 +1,61 @@ -# -*- mode:org; mode:auto-fill; fill-column:80; coding:utf-8; -*- +# -*- mode:org; mode:auto-fill; fill-column:80; coding:utf-8; tab-width:8; -*- VobSub2SRT is a simple command line program to convert =.idx= / =.sub= subtitles into =.srt= text subtitles by using OCR. It is based on code from the -[[http://www.mplayerhq.hu][MPlayer project]] - a really really great movie player. Some minor parts are - copied from [[http://ffmpeg.org/][ffmpeg/avutil]] headers. [[http://code.google.com/p/tesseract-ocr/][Tesseract]] is used as OCR software. +[[https://www.mplayerhq.hu][MPlayer project]] - a pretty decent movie player. Some minor parts are + copied from [[https://ffmpeg.org/][ffmpeg/avutil]] headers. [[https://code.google.com/p/tesseract-ocr/][Tesseract]] is used as OCR software. vobsub2srt is released under the GPL3+ license. The MPlayer code included is GPL2+ licensed. The quality of the OCR depends on the text in the subtitles. Currently the code does not use any preprocessing. But I'm currently looking into adding filters -and scaling options to improve the OCR. You can correct mistakes in the =.srt= -files with a text editor or a special subtitle editor. +to improve the OCR. You can correct mistakes in the =.srt= files with a text +editor or a subtitle editor. + +** July 2026 +- I have been working on a completely new codebase for better support across systems + and multiple formats. This may take some time, as I am learning FFmpeg's API. + When it is ready, it will have its own repository separate from this. Possible + AArch64 (or more like GCC 12, since that is the main issue) support as well after + acquiring a PinePhone. That goes for this project too. + +- Added conditional libPNG header check inside vobsub2srt.c++ for + compatibility with NixOS and others. +- MPlayer vobsub.c memory fixes/refactor soon. Results are promising + with increased speed and accuracy. (on hiatus) + +** Jun 2026 +- PNG export added, cast vobsubid to avoid left shift. +- Image inversion added. Code by Ethan Dye, used with + permission (https://github.com/ecdye/VobSub2SRT) +- Scaling code removed. It never did seem to work out well in my tests. +- Tesseract options added to improve accuracy somewhat. + +** New for April/May 2026 +- Scaling of subtitles implemented (try --scale) +- Final memory leak closed in vobsub.c + +** New for March 2026 +- Memory safety +- MPlayer verbosity separated from realtime text output + +** Upcoming: +- Subtitle anti-aliasing for further accuracy enhancement. + * Building -You need tesseract. You also need cmake and a gcc to build it. -With Ubuntu 12.10 you can install the dependencies with +You need libPNG, Tesseract, CMake and GCC to build =vobsub2srt=. +With a Debian-based distribution, you can install the dependencies with: #+BEGIN_EXAMPLE - sudo apt-get install libtiff5-dev libtesseract-dev tesseract-ocr-eng build-essential cmake pkg-config + sudo apt-get install libpng-dev libtiff5-dev libtesseract-dev build-essential cmake pkg-config #+END_EXAMPLE -You should also install the tesseract data for the languages you want to use! -Note that the support for tesseract 2 is deprecated and will be removed in the -future! +You also need to install the tesseract data for the languages you want to use. + +#+BEGIN_EXAMPLE + sudo apt-get install tesseract-lang-eng +#+END_EXAMPLE #+BEGIN_EXAMPLE ./configure @@ -30,8 +63,21 @@ future! sudo make install #+END_EXAMPLE -This should install the program vobsub2srt to =/usr/local/bin=. You can +Note that support for Tesseract <4 is deprecated. + +Building from NixOS (Tested with 26.05): +#+BEGIN_EXAMPLE +nix-env -iA nixos.git nixos.gcc nixos.cmake nixos.tesseract nixos.libtiff nixos.libpng nixos.zlib +git clone https://github.com/csingleplus/VobSub2SRT && cd VobSub2SRT +cmake -B build +cmake --build build +sudo cmake --install build +#+END_EXAMPLE + +This should install the program vobsub2srt to =/usr/local/bin=. +Run configure with -DCMAKE_INSTALL_PREFIX= for elsewhere. You can uninstall vobsub2srt with =sudo make uninstall=. + ** Static binary I recommend using the dynamic binary! However if you really need a static binary you can add the flag =-DBUILD_STATIC=ON= to the =./configure= call. But be @@ -40,10 +86,10 @@ static library files for tesseract, libtill, libavutils, and for their dependencies as well. On Ubuntu 12.04 the static libraries are only included in the dev packages! You probably also need the Gold linker. -For Ubuntu 12.04 you need the following extra packages: +For Ubuntu 12.04 you need the following extra packages: (but this branch likely does not work with such an old distro.) #+BEGIN_EXAMPLE - sudo apt-get install libleptonica-dev libpng12-dev libwebp-dev libgif-dev zlib1g-dev libjpeg-dev binutils-gold + sudo apt-get install libleptonica-dev libpng-dev libwebp-dev libgif-dev zlib1g-dev libjpeg-dev binutils-gold #+END_EXAMPLE If linking fails with undefined references then checking what other dependencies @@ -51,52 +97,11 @@ your version of leptonica has is a good starting point. You can do this by running =ldd /usr/lib/liblept.so= (or whatever the path to leptonica is on your system). Add those dependencies to =CMakeModules/FindTesseract.cmake=. -** Ubuntu PPA and .deb packages -I have created a [[https://launchpad.net/~ruediger-c-plusplus/+archive/vobsub2srt][PPA (Personal Package Archive)]] to make installation on -Ubuntu easy. Simply add the PPA to your apt-get sources and run an update and -you can install the =vobsub2srt= package: - -#+BEGIN_EXAMPLE - sudo add-apt-repository ppa:ruediger-c-plusplus/vobsub2srt - sudo apt-get update - sudo apt-get install vobsub2srt -#+END_EXAMPLE - *** .deb (Debian/Ubuntu) You can build a *.deb package (Debian/Ubuntu) with =make package=. The package is created in the =build= directory. -You can also create a source package and upload it to your own PPA by using the -=UploadPPA.cmake=. But this is only recommended for people experienced with -cmake and creating Debian packages. - -** Homebrew -Vobsub2srt contains a formula for [[http://mxcl.github.com/homebrew/][Homebrew]] (a package manager for OS X). It can -be installed by using the following commands: - -#+BEGIN_EXAMPLE - brew install --with-all-languages tesseract - brew install --HEAD https://github.com/ruediger/VobSub2SRT/raw/master/packaging/vobsub2srt.rb -#+END_EXAMPLE - -** Gentoo ebuild -An [[http://en.wikipedia.org/wiki/Ebuild][ebuild]] for Gentoo Linux is also available. You can make it available to -emerge with the following steps -#+BEGIN_EXAMPLE - sudo mkdir -p /usr/local/portage/media-video/vobsub2srt/ - wget https://github.com/ruediger/VobSub2SRT/raw/master/packaging/vobsub2srt-9999.ebuild - sudo mv vobsub2srt-9999.ebuild /usr/local/portage/media-video/vobsub2srt/ - cd /usr/local/portage/media-video/vobsub2srt/ - sudo ebuild vobsub2srt-999.ebuild digest -#+END_EXAMPLE - -You should be able to install vobsub2srt with =emerge vobsub2srt= now. If you -want to use a newer version (3+) of tesseract you have to use layman. -See [[https://github.com/ruediger/VobSub2SRT/issues/13][#13]] for details. -** Arch AUR -There also exist a [[https://wiki.archlinux.org/index.php/PKGBUILD][PKGBUILD]] file for Arch Linux in AUR: -https://aur.archlinux.org/packages/vobsub2srt-git * Usage vobsub2srt converts subtitles in VobSub (=.idx= / =.sub=) format into subtitles in =.srt= format. VobSub subtitles consist of two or three files called @@ -109,48 +114,33 @@ simply call with =Filename= being the file name of the subtitle files *WITHOUT* the extension (=.idx= / =.sub=). vobsub2srt writes the subtitles to a file called -=Filename.srt=. +=Filename.srt=. You can see the subtitles as they are decoded with =--show=. If a subtitle file contains more than one language you can use the =--lang= parameter to set the correct language (Use =--langlist= to find out about the languages in the file). For some languages you might need to set the tesseract language yourself (e.g., chi_tra/chi_sim for traditional or simplified chinese -characters). You can use =--tesseract-lang= to do this. In most cases this +characters). You can use =--tesseract-lang= to do this. Multilingual subtitles +may be written by combining langcodes as such: eng+fra. In most cases this should however be autodetected. If you want to dump the subtitles as images (e.g. to check for correct ocr) you -can use the =--dump-images= flag. +can use the =--dump-png= flag. Use =--help= or read the manpage to get more information about the options of vobsub2srt. * Bug reports Please submit bug reports or feature requests to the -[[https://github.com/ruediger/VobSub2SRT/issues][issue tracker on GitHub]]. If you do not have a GitHub account and feel -uncomfortable creating one then feel free to send an e-mail to - instead. +[[https://github.com/csingleplus/VobSub2SRT/issues][issue tracker on GitHub]]. If you have problems with a specific subtitle file then please check if -it works in mplayer first. If it does not then please report the bug to -mplayer as well and link to the mplayer bug report. - -For bug reports please run =vobsub2srt= with the =--verbose= option and copy -and paste the full output to the bug report. - -* Contributors -Most code is from the MPlayer project. -- Armin Häberling wrote a patch to fix an issue with - multiple instances of the same subtitle in result file (21af426) -- James Harris wrote the formula for Homebrew (54f311d6) -- Leo Koppelkamm reported and fixed issue #5 and problems with long filenames - (b903074c, 36ec8da, d3602d6) -- Till Korten wrote the ebuild script (#13) -- Andreasf fixed missing libavutil include path (3a175eb, #15) -- Michal Gawlik fixed the overlapping issue (5b2ccabc55f, #29, #32) -- "bit" made sure no trailing whitespace are written to the SRT (3a59dc278abc2, #38) -- Baudouin Raoult for various fixes (028f742, #44, b722a03, #42, 7293ac2, #40) -- Justyn Butler added the y-threshold support (f873761, #43) -- James Laird-Wah added min-width/height support and fixed other issues (41c6844, #48, #46) -- Filirom1 fixed a minor issue (4ed58c2, #49) -* To Do -- implement preprocessing (first step scaling. Code available in =spudec.c=) +it works in mplayer first. Also, you may need to replace the palette line +in your .idx file to this, a plain white-on-black palette for better accuracy. + +#+BEGIN_SRC + palette: 000000,ffffff,000000,000000,000000,ffffff,000000,000000,000000,ffffff,000000,000000,000000,ffffff,000000,000000 +#+END_SRC + +For bug reports please run =vobsub2srt= with the =--verbose= option set to 2, +and copy and paste the first 50~ lines from the beginning of the problem to the bug report. diff --git a/debian/copyright b/debian/copyright index a1d35ad..55f631a 100644 --- a/debian/copyright +++ b/debian/copyright @@ -24,14 +24,14 @@ GPLv3+: it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-3'. @@ -47,4 +47,5 @@ mplayer part vobsub2srt part License: GPLv3+ - Copyright (C) 2010-2016 Rüdiger Sonderfeld + Copyright © 2010-2016 Rüdiger Sonderfeld + Copyright © 2026 Christopher Ogloff diff --git a/doc/vobsub2srt.1 b/doc/vobsub2srt.1 index 90b33fd..87e2fe5 100644 --- a/doc/vobsub2srt.1 +++ b/doc/vobsub2srt.1 @@ -1,52 +1,66 @@ -.TH vobsub2srt 1 "17 June 2013" +.TH vobsub2srt 1.2 "17 June 2026" .SH NAME vobsub2srt \- converts vobsub (.idx/.sub) into .srt subtitles .SH SYNOPSIS \fBvobsub2srt\fR [\fIOPTION\fR] \fIFILENAME\fR .SH DESCRIPTION .PP -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. +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. .SH OPTIONS .TP \fIFILENAME\fR File name of the subtitles \fBWITHOUT\fR the .idx or .sub extension. The .srt subtitles are written to a file called \fIFILENAME\fR.srt. .TP -\fB\-\-dump\-images\fR -Dump the subtitles as images (format \fIFILENAME\fR-\fINUMBER\fR.pgm in PGM format). +\fB\-\-dump\-pgm\fR +Extract the subtitles as NetPBM PGM images (format \fIFILENAME\fR-\fINUMBER\fR.pgm in PGM format). (Obsolete) +.TP +\fB\-\-dump\-png\fR +Extract the subtitles to sequential PNG files. +.TP +\fB\-\-show\fR +Print text output to terminal (stdout). .TP \fB\-\-verbose\fR -Print more information about the file (e.g. subtitle languages) +Print verbose information about the subtitle decoding process. .TP \fB\-\-lang\fR \fIlanguage\fR -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. +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. .TP \fB\-\-langlist\fR List languages and exit. .TP \fB\-\-index\fR \fIindex\fR -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! +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! .TP \fB\-\-ifo\fR \fIifo-file\fR To use a specific IFO file. Default: \fIFILENAME\fR.IFO is tried. IFO file is optional! .TP \fB\-\-tesseract-lang\fR \fIlanguage\fR -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. +Set the language to be used by Tesseract. This is auto detected and normally does not need to be changed. +If however you need special language settings (e.g., deu-frak, chi_sim, chi_tra) use this option. .TP \fB\-\-tesseract-data\fR \fIpath\fR -Set path to tesseract-data. +Set path to Tesseract data. (e.g. /usr/share/tessdata_best, otherwise auto-detect standard Tesseract data) .TP \fB\-\-blacklist\fR \fIblacklist\fR Blacklist characters for OCR (e.g. |\\/`_~<>) .TP \fB\-\-y-threshold\fR \fIthreshold\fR -Y (luminance) threshold below which colors treated as black (Default: 0). +Y (luminance) threshold below which colors treated as black (Default: 16). .TP \fB\-\-min-width\fR \fIwidth\fR -Minimum width in pixels to consider a subpicture for OCR (Default: 9). +Minimum width in pixels to consider a subpicture for OCR (Default: 8). .TP \fB\-\-min-height\fR \fIheight\fR Minimum height in pixels to consider a subpicture for OCR (Default: 1). .SH EXAMPLES +.nf + $ \fBvobsub2srt \-\-show foobar\fR +.fi +Prints the subtitles as they are passed through OCR.\fR .nf $ \fBvobsub2srt \-\-lang en foobar\fR .fi @@ -55,7 +69,11 @@ Converts the English language subtitles from the VobSub files \fIfoobar.idx\fR/\ $ \fBvobsub2srt \-\-lang zh \-\-tesseract-lang chi_sim foobar\fR .fi Converts the chinese language subtitles using simplified chinese (chi_sim) characters. + .SH HOMEPAGE -For more information see \fIhttp://github.com/ruediger/VobSub2SRT\fR -.SH AUTHOR +For more information see \fIhttps://github.com/csingleplus/VobSub2SRT\fR. +Original VobSub2SRT code available at \fIhttps://github.com/ruediger/VobSub2SRT\fR. + +.SH AUTHORS R\[:u]diger Sonderfeld <\fIruediger -AT- c-plusplus -DOT- de\fR> +Christopher Ogloff <\fIchris.ogloff@gmail.com\fR> \fIhttps://github.com/csingleplus\fR diff --git a/mplayer/CMakeLists.txt b/mplayer/CMakeLists.txt index 4f07674..016dd40 100644 --- a/mplayer/CMakeLists.txt +++ b/mplayer/CMakeLists.txt @@ -6,8 +6,6 @@ set(mplayer_sources mp_msg.h spudec.c spudec.h - unrar_exec.c - unrar_exec.h vobsub.c vobsub.h ) diff --git a/mplayer/README b/mplayer/README index bedd401..853f62b 100644 --- a/mplayer/README +++ b/mplayer/README @@ -1,3 +1,10 @@ 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. I added comments prefixed with R: to mark changes from the original MPlayer code. + +/*****************************************************/ +2026-03-03: Removed ancient unrar code. * +2026-04-23: Fixed memory leak in vobsub_open (lineptr)* + * +-Christopher Ogloff * +\*****************************************************/ \ No newline at end of file diff --git a/mplayer/mp_msg.c b/mplayer/mp_msg.c index dc0bbb3..48e82ee 100644 --- a/mplayer/mp_msg.c +++ b/mplayer/mp_msg.c @@ -20,12 +20,11 @@ #include #include #include - -#if 0 // R: no iconv, charset stuff +/* #include "config.h" +//moved from libavutil/avstring.h #include "osdep/getch2.h" -#endif - +*/ #ifdef CONFIG_ICONV #include #include @@ -43,8 +42,12 @@ int mp_msg_color = 0; int mp_msg_module = 0; #ifdef CONFIG_ICONV char *mp_msg_charset = NULL; +// only used to simplify freeing get_term_charset +// result, even when it was overwritten by command-line options. +char *term_charset_ptr_to_free = NULL; static char *old_charset = NULL; static iconv_t msgiconv; +static iconv_t inv_msgiconv = (iconv_t)(-1); #endif const char* filename_recode(const char* filename) @@ -52,7 +55,6 @@ const char* filename_recode(const char* filename) #if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET) return filename; #else - static iconv_t inv_msgiconv = (iconv_t)(-1); static char recoded_filename[MSGSIZE_MAX]; size_t filename_len, max_path; char* precoded; @@ -68,7 +70,7 @@ const char* filename_recode(const char* filename) filename_len = strlen(filename); max_path = MSGSIZE_MAX - 4; precoded = recoded_filename; - if (iconv(inv_msgiconv, &filename, &filename_len, + if (iconv(inv_msgiconv, (char **)&filename, &filename_len, &precoded, &max_path) == (size_t)(-1) && errno == E2BIG) { precoded[0] = precoded[1] = precoded[2] = '.'; precoded += 3; @@ -80,17 +82,30 @@ const char* filename_recode(const char* filename) void mp_msg_init(void){ int i; -#if 0 // R: don't check MPLAYER_VERBOSE environment var char *env = getenv("MPLAYER_VERBOSE"); if (env) verbose = atoi(env); -#endif for(i=0;i #ifdef __cplusplus extern "C" { #endif - // defined in mplayer.c and mencoder.c extern int verbose; @@ -52,8 +52,8 @@ extern int verbose; #define MSGT_CPLAYER 1 // console player (mplayer.c) #define MSGT_GPLAYER 2 // gui player -#define MSGT_VO 3 // libvo -#define MSGT_AO 4 // libao +#define MSGT_VO 3 // libvo +#define MSGT_AO 4 // libao #define MSGT_DEMUXER 5 // demuxer.c (general stuff) #define MSGT_DS 6 // demux stream (add/read packet etc) @@ -68,26 +68,26 @@ extern int verbose; #define MSGT_DECAUDIO 12 // av decoder #define MSGT_DECVIDEO 13 -#define MSGT_SEEK 14 // seeking code -#define MSGT_WIN32 15 // win32 dll stuff -#define MSGT_OPEN 16 // open.c (stream opening) -#define MSGT_DVD 17 // open.c (DVD init/read/seek) +#define MSGT_SEEK 14 // seeking code +#define MSGT_WIN32 15 // win32 dll stuff +#define MSGT_OPEN 16 // open.c (stream opening) +#define MSGT_DVD 17 // open.c (DVD init/read/seek) -#define MSGT_PARSEES 18 // parse_es.c (mpeg stream parser) -#define MSGT_LIRC 19 // lirc_mp.c and input lirc driver +#define MSGT_PARSEES 18 // parse_es.c (mpeg stream parser) +#define MSGT_LIRC 19 // lirc_mp.c and input lirc driver #define MSGT_STREAM 20 // stream.c -#define MSGT_CACHE 21 // cache2.c +#define MSGT_CACHE 21 // cache2.c #define MSGT_MENCODER 22 -#define MSGT_XACODEC 23 // XAnim codecs +#define MSGT_XACODEC 23 // XAnim codecs -#define MSGT_TV 24 // TV input subsystem +#define MSGT_TV 24 // TV input subsystem -#define MSGT_OSDEP 25 // OS-dependent parts +#define MSGT_OSDEP 25 // OS-dependent parts -#define MSGT_SPUDEC 26 // spudec.c +#define MSGT_SPUDEC 26 // spudec.c #define MSGT_PLAYTREE 27 // Playtree handeling (playtree.c, playtreeparser.c) @@ -140,32 +140,35 @@ extern int mp_msg_level_all; void mp_msg_init(void); +void mp_msg_uninit(void); int mp_msg_test(int mod, int lev); -//#include "config.h" // R: not needed +//#include "config.h" C: unused in vobsub2srt. +void mp_msg_va(int mod, int lev, const char *format, va_list va); #ifdef __GNUC__ void mp_msg(int mod, int lev, const char *format, ... ) __attribute__ ((format (printf, 3, 4))); -#if 0 // R: not needed and args... doesn't work with -ansi + /* # ifdef MP_DEBUG # define mp_dbg(mod,lev, args... ) mp_msg(mod, lev, ## args ) # else -# define mp_dbg(mod,lev, args... ) /* only useful for developers */ + + only useful for developers, disable but check syntax +# define mp_dbg(mod,lev, args... ) do { if (0) mp_msg(mod, lev, ## args ); } while (0) # endif -#endif -#else // not GNU C -void mp_msg(int mod, int lev, const char *format, ... ); +#else not GNU C +void mp_msg(int mod, int lev, const char *format, ... ); # ifdef MP_DEBUG # define mp_dbg(mod,lev, ... ) mp_msg(mod, lev, __VA_ARGS__) # else -# define mp_dbg(mod,lev, ... ) /* only useful for developers */ + only useful for developers, disable but check syntax +# define mp_dbg(mod,lev, ... ) do { if (0) mp_msg(mod, lev, __VA_ARGS__); } while (0) # endif + */ #endif /* __GNUC__ */ const char* filename_recode(const char* filename); - #ifdef __cplusplus } #endif - #endif /* MPLAYER_MP_MSG_H */ diff --git a/mplayer/spudec.c b/mplayer/spudec.c index f9f2e91..dfd9f56 100644 --- a/mplayer/spudec.c +++ b/mplayer/spudec.c @@ -26,10 +26,32 @@ * with MPlayer; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* FFmpeg/libavutil licensing information: -// #include "config.h" -#include "mp_msg.h" +common.h is copyright (c) 2006 Michael Niedermayer +bswap.h is copyright (C) 2006 by Michael Niedermayer +intreadwrite.h does not contain a specific copyright notice. + +the code is licensed under LGPL 2 with the following license header +FFmpeg is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +FFmpeg is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with FFmpeg; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "mp_msg.h" +#include #include #include #include @@ -37,14 +59,11 @@ #include #include #include -//#include "libvo/sub.h" // R: no OSD stuff needed -//#include "libvo/video_out.h" // R: no OSD stuff needed int sub_pos = 100; // R: copied from libvo/sub.c #include "spudec.h" #include "vobsub.h" -// #include "libswscale/swscale.h" // R: no swscalar gaussian aamode #define FFMAX(a,b) ((a) > (b) ? (a) : (b)) #define FFMIN(a,b) ((a) > (b) ? (b) : (a)) @@ -57,7 +76,7 @@ int sub_pos = 100; // R: copied from libvo/sub.c 4: uses swscaler gaussian (this is the only one that looks good) R: Not supported (libswscale dependency removed) */ -int spu_aamode = 3; +int spu_aamode = 2; int spu_alignment = -1; float spu_gaussvar = 1.0; @@ -224,7 +243,7 @@ static inline void spudec_cut_image(spudec_handle_t *this) static int spudec_alloc_image(spudec_handle_t *this, int stride, int height) { - if (this->width > stride) // just a safeguard + if (this->width > (unsigned int)stride) // just a safeguard this->width = stride; this->stride = stride; this->height = height; @@ -295,7 +314,7 @@ static int apply_palette_crop(spudec_handle_t *this, color = (color >> 16) & 0xff; // convert to MPlayer-style gray/alpha palette color = FFMIN(color, alpha); - pal[i] = (-alpha << 8) | color; + pal[i] = ((256 - alpha) << 8) | color; } src = this->pal_image + crop_y * this->pal_width + crop_x; pal2gray_alpha(pal, src, this->pal_width, @@ -430,7 +449,7 @@ static void compute_palette(spudec_handle_t *this, packet_t *packet) static void spudec_process_control(spudec_handle_t *this, int pts100) { - int a,b,c,d; /* Temporary vars */ + unsigned int a,b,c,d; /* Temporary vars */ unsigned int date, type; unsigned int off; unsigned int start_off = 0; @@ -463,7 +482,7 @@ static void spudec_process_control(spudec_handle_t *this, int pts100) /* Menu ID, 1 byte */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n"); /* shouldn't a Menu ID type force display start? */ - start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date; + start_pts = pts100 < 0 && (unsigned int)(-pts100) >= date ? 0 : pts100 + date; end_pts = UINT_MAX; display = 1; this->is_forced_sub=~0; // current subtitle is forced @@ -471,7 +490,7 @@ static void spudec_process_control(spudec_handle_t *this, int pts100) case 0x01: /* Start display */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n"); - start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date; + start_pts = pts100 < 0 && (unsigned int)(-pts100) >= date ? 0 : pts100 + date; end_pts = UINT_MAX; display = 1; this->is_forced_sub=0; @@ -479,7 +498,7 @@ static void spudec_process_control(spudec_handle_t *this, int pts100) case 0x02: /* Stop display */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n"); - end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date; + end_pts = pts100 < 0 && (unsigned int)(-pts100) >= date ? 0 : pts100 + date; break; case 0x03: /* Palette */ @@ -553,7 +572,7 @@ static void spudec_process_control(spudec_handle_t *this, int pts100) continue; if (end_pts == UINT_MAX && start_off != next_off) { end_pts = get_be16(this->packet + next_off) * 1024; - end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1; + end_pts = (unsigned int)(1 - pts100) >= end_pts ? 0 : pts100 + end_pts - 1; } if (end_pts > 0) { packet_t *packet = calloc(1, sizeof(packet_t)); @@ -581,20 +600,7 @@ static void spudec_process_control(spudec_handle_t *this, int pts100) static void spudec_decode(spudec_handle_t *this, int pts100) { -#if 0 // R: OSD stuff removed - if (!this->hw_spu) - spudec_process_control(this, pts100); - else if (pts100 >= 0) { - static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 }; - static vo_mpegpes_t *pkg=&packet; - packet.data = this->packet; - packet.size = this->packet_size; - packet.timestamp = pts100; - this->hw_spu->draw_frame((uint8_t**)&pkg); - } -#else spudec_process_control(this, pts100); -#endif } int spudec_changed(void * this) @@ -623,7 +629,8 @@ void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pt if (spu->packet != NULL) { spu->packet_size = len2; if (len > len2) { - mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2); + mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm error: Raccoons encountered in stream\n" + "invalid frag len / len2: %d / %d \n", len, len2); return; } memcpy(spu->packet, packet, len); @@ -633,7 +640,7 @@ void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pt } else { // Continue current fragment if (spu->packet_size < spu->packet_offset + len){ - mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n"); + mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment.\n"); spu->packet_size = spu->packet_offset = 0; return; } else { @@ -738,7 +745,7 @@ void spudec_set_forced_subs_only(void * const this, const unsigned int flag) } } -void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)) +void spudec_draw(void *this, void (*draw_alpha)(int x0, int y0, int w, int h, unsigned char* src, unsigned char *srca, int stride)) { spudec_handle_t *spu = this; if (spudec_visible(spu)) @@ -819,7 +826,7 @@ static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned } src_step = (delta_src << 16) / delta_tar >>1; for (t = 0; t<=delta_tar; src += (src_step << 1), t++){ - table[t].position= FFMIN(src >> 16, end_src - 1); + table[t].position= FFMIN((unsigned int)(src >> 16), end_src - 1); table[t].right_down = src & 0xffff; table[t].left_up = 0x10000 - table[t].right_down; } @@ -857,36 +864,7 @@ static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y } } -#if 0 // R: removed sws scaling -static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, - int ds, const unsigned char* s1, unsigned char* s2, - int sw, int sh, int ss) -{ - struct SwsContext *ctx; - static SwsFilter filter; - static int firsttime = 1; - static float oldvar; - int i; - - if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH); - if (firsttime) { - filter.lumH = filter.lumV = - filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0); - sws_normalizeVec(filter.lumH, 1.0); - firsttime = 0; - oldvar = spu_gaussvar; - } - - ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL); - sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds); - for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1; - sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds); - for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0; - sws_freeContext(ctx); -} -#endif - -void spudec_draw_scaled(void *me, 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)) +void spudec_draw_scaled(void *me, 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)) { spudec_handle_t *spu = me; scale_pixel *table_x; @@ -914,6 +892,12 @@ void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*dra spu->scaled_start_row = spu->start_row * scaley / 0x100; spu->scaled_width = spu->width * scalex / 0x100; spu->scaled_height = spu->height * scaley / 0x100; + if (spu->scaled_width == 0 || spu->scaled_height == 0) { + mp_msg(MSGT_SPUDEC, MSGL_FATAL, + "Fatal: scaled image resulted in null dimensions! (%u x %u from %u x %u\n", + spu->scaled_width, spu->scaled_height, spu->width, spu->height); + goto nothing_to_do; + } /* Kludge: draw_alpha needs width multiple of 8 */ spu->scaled_stride = (spu->scaled_width + 7) & ~7; if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) { @@ -938,13 +922,6 @@ void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*dra } switch(spu_aamode&15) { case 4: -#if 0 // R: no swscalar gaussian aa supported - sws_spu_image(spu->scaled_image, spu->scaled_aimage, - spu->scaled_width, spu->scaled_height, spu->scaled_stride, - spu->image, spu->aimage, spu->width, spu->height, spu->stride); -#else - mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: no swsscalar gaussian aa supported"); -#endif break; case 3: table_x = calloc(spu->scaled_width, sizeof(scale_pixel)); @@ -1225,10 +1202,6 @@ void spudec_update_palette(void * this, unsigned int *palette) spudec_handle_t *spu = this; if (spu && palette) { memcpy(spu->global_palette, palette, sizeof(spu->global_palette)); -#if 0 // R: OSD stuff removed - if(spu->hw_spu) - spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette); -#endif } } @@ -1245,27 +1218,8 @@ void spudec_set_font_factor(void * this, double factor) /* code taken from ffmpeg/libavutil. intreadwrite.h and bswap.h - -common.h is copyright (c) 2006 Michael Niedermayer -bswap.h is copyright (C) 2006 by Michael Niedermayer -intreadwrite.h does not contain a specific copyright notice. - -the code is licensed under LGPL 2 with the following license header - -FFmpeg is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -FFmpeg is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with FFmpeg; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ +see first page for license information. +*/ union unaligned_32 { uint32_t l; } __attribute__((packed)) __attribute__((may_alias)); #define AV_RN32(p) (((const union unaligned_32 *) (p))->l) @@ -1286,6 +1240,8 @@ static __attribute__((always_inline)) inline uint32_t __attribute__((const)) av_ #endif // AV_HAVE_BIG_ENDIAN #endif // AV_RB32 +/* end ffmpeg/libavutil code */ + static void spudec_parse_extradata(spudec_handle_t *this, uint8_t *extradata, int extradata_len) { @@ -1414,6 +1370,7 @@ void spudec_free(void *this) } } +/* #if 0 // R: not necessary void spudec_set_hw_spu(void *this, const vo_functions_t *hw_spu) { @@ -1424,8 +1381,8 @@ void spudec_set_hw_spu(void *this, const vo_functions_t *hw_spu) hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette); } #endif - -#define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly +*/ +#define MP_NOPTS_VALUE (INT64_MIN) //both int64_t and double should be able to represent this exactly /** * palette must contain at least 256 32-bit entries, otherwise crashes @@ -1480,8 +1437,10 @@ void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride, } // R: added to extract data -void spudec_get_data(void *this, const unsigned char **image, size_t *image_size, unsigned *width, unsigned *height, - unsigned *stride, unsigned *start_pts, unsigned *end_pts) +// C: updated to add scaling functions. +void spudec_get_data(void *this, const unsigned char **image, size_t *image_size, + unsigned *width, unsigned *height, unsigned *stride, + unsigned *start_pts, unsigned *end_pts) { spudec_handle_t *spu = this; *image = spu->image; @@ -1492,3 +1451,27 @@ void spudec_get_data(void *this, const unsigned char **image, size_t *image_size *start_pts = spu->start_pts; *end_pts = spu->end_pts; } + +void spudec_get_data_scaled(void *this, const unsigned char **scaled_image, size_t *scaled_image_size, + unsigned *width, unsigned *height, unsigned *stride, unsigned *start_pts, + unsigned *end_pts, unsigned *scaled_width, unsigned *scaled_height, + unsigned *scaled_stride) { + + spudec_handle_t *spu = this; + *scaled_image = spu->scaled_image; + *scaled_image_size = spu->scaled_image_size; + *width = spu->width; + *height = spu->height; + *stride = spu->stride; + *start_pts = spu->start_pts; + *end_pts = spu->end_pts; + *scaled_width = spu->scaled_width; + *scaled_height = spu->scaled_height; + *scaled_stride = spu->scaled_stride; +} + +void spudec_get_frame_size(void *this, unsigned *frame_width, unsigned *frame_height) { + spudec_handle_t *spu = this; + if (frame_width) *frame_width = spu->orig_frame_width; + if (frame_height) *frame_height = spu->orig_frame_height; +} diff --git a/mplayer/spudec.h b/mplayer/spudec.h index c79c1e0..c7f1c71 100644 --- a/mplayer/spudec.h +++ b/mplayer/spudec.h @@ -47,9 +47,23 @@ void spudec_set_paletted(void *self, const uint8_t *pal_img, int stride, const void *palette, int x, int y, int w, int h, double pts, double endpts); + /// call this after spudec_assemble and spudec_heartbeat to get the packet data -void spudec_get_data(void *self, const unsigned char **image, size_t *image_size, unsigned *width, unsigned *height, - unsigned *stride, unsigned *start_pts, unsigned *end_pts); + void spudec_get_data(void *self, const unsigned char **image, size_t *image_size, + unsigned *width, unsigned *height, unsigned *stride, + unsigned *start_pts, unsigned *end_pts); + + /** + * Get scaled SPU image data. If scale_width/height are non-zero, + * the scaled image is returned; otherwise keep original resolution. + */ + void spudec_get_data_scaled(void *self, const unsigned char **scaled_image, size_t *scaled_image_size, + unsigned *width, unsigned *height, unsigned *stride, + unsigned *start_pts, unsigned *end_pts, + unsigned int *scaled_width, unsigned int *scaled_height, + unsigned int *scaled_stride); + + void spudec_get_frame_size(void *self, unsigned *frame_width, unsigned *frame_height); #ifdef __cplusplus } diff --git a/mplayer/unrar_exec.c b/mplayer/unrar_exec.c deleted file mode 100644 index 6de8c59..0000000 --- a/mplayer/unrar_exec.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * List files and extract file from rars by using external executable unrar. - * - * Copyright (C) 2005 Jindrich Makovicka - * Copyright (C) 2007 Ulion - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "unrar_exec.h" - -#include "mp_msg.h" - -#define UNRAR_LIST 1 -#define UNRAR_EXTRACT 2 - -char* unrar_executable = NULL; - -static FILE* launch_pipe(pid_t *apid, const char *executable, int action, - const char *archive, const char *filename) -{ - if (!executable || access(executable, R_OK | X_OK)) return NULL; - if (access(archive, R_OK)) return NULL; - { - int mypipe[2]; - pid_t pid; - - if (pipe(mypipe)) { - mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Cannot create pipe.\n"); - return NULL; - } - - pid = fork(); - if (pid == 0) { - /* This is the child process. Execute the unrar executable. */ - close(mypipe[0]); - // Close MPlayer's stdin, stdout and stderr so the unrar binary - // can not mess them up. - // TODO: Close all other files except the pipe. - close(0); close(1); close(2); - // Assign new stdin, stdout and stderr and check they actually got the - // right descriptors. - if (open("/dev/null", O_RDONLY) != 0 || dup(mypipe[1]) != 1 - || open("/dev/null", O_WRONLY) != 2) - _exit(EXIT_FAILURE); - if (action == UNRAR_LIST) - execl(executable, executable, "v", archive, NULL); - else if (action == UNRAR_EXTRACT) - execl(executable, executable, "p", "-inul", "-p-", - archive,filename,NULL); - mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Cannot execute %s\n", executable); - _exit(EXIT_FAILURE); - } - if (pid < 0) { - /* The fork failed. Report failure. */ - mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Fork failed\n"); - return NULL; - } - /* This is the parent process. Prepare the pipe stream. */ - close(mypipe[1]); - *apid = pid; - if (action == UNRAR_LIST) - mp_msg(MSGT_GLOBAL, MSGL_V, - "UnRAR: call unrar with command line: %s v %s\n", - executable, archive); - else if (action == UNRAR_EXTRACT) - mp_msg(MSGT_GLOBAL, MSGL_V, - "UnRAR: call unrar with command line: %s p -inul -p- %s %s\n", - executable, archive, filename); - return fdopen(mypipe[0], "r"); - } -} - -#define ALLOC_INCR 1 * 1024 * 1024 -int unrar_exec_get(unsigned char **output, unsigned long *size, - const char *filename, const char *rarfile) -{ - int bufsize = ALLOC_INCR, bytesread; - pid_t pid; - int status = 0; - FILE *rar_pipe; - - rar_pipe=launch_pipe(&pid,unrar_executable,UNRAR_EXTRACT,rarfile,filename); - if (!rar_pipe) return 0; - - *size = 0; - - *output = malloc(bufsize); - - while (*output) { - bytesread=fread(*output+*size, 1, bufsize-*size, rar_pipe); - if (bytesread <= 0) - break; - *size += bytesread; - if (*size == bufsize) { - char *p; - bufsize += ALLOC_INCR; - p = realloc(*output, bufsize); - if (!p) - free(*output); - *output = p; - } - } - fclose(rar_pipe); - pid = waitpid(pid, &status, 0); - if (!*output || !*size || (pid == -1 && errno != ECHILD) || - (pid > 0 && status)) { - free(*output); - *output = NULL; - *size = 0; - return 0; - } - if (bufsize > *size) { - char *p = realloc(*output, *size); - if (p) - *output = p; - } - mp_msg(MSGT_GLOBAL, MSGL_V, "UnRAR: got file %s len %lu\n", filename,*size); - return 1; -} - -#define PARSE_NAME 0 -#define PARSE_PROPS 1 - -int unrar_exec_list(const char *rarfile, ArchiveList_struct **list) -{ - char buf[1024], fname[1024]; - char *p; - pid_t pid; - int status = 0, file_num = -1, ignore_next_line = 0, state = PARSE_NAME; - FILE *rar_pipe; - ArchiveList_struct *alist = NULL, *current = NULL, *new; - - rar_pipe = launch_pipe(&pid, unrar_executable, UNRAR_LIST, rarfile, NULL); - if (!rar_pipe) return -1; - while (fgets(buf, sizeof(buf), rar_pipe)) { - int packsize, unpsize, ratio, day, month, year, hour, min; - int llen = strlen(buf); - // If read nothing, we got a file_num -1. - if (file_num == -1) - file_num = 0; - if (buf[llen-1] != '\n') - // The line is too long, ignore it. - ignore_next_line = 2; - if (ignore_next_line) { - --ignore_next_line; - state = PARSE_NAME; - continue; - } - // Trim the line. - while (llen > 0 && strchr(" \t\n\r\v\f", buf[llen-1])) - --llen; - buf[llen] = '\0'; - p = buf; - while (*p && strchr(" \t\n\r\v\f", *p)) - ++p; - if (!*p) { - state = PARSE_NAME; - continue; - } - - if (state == PARSE_PROPS && sscanf(p, "%d %d %d%% %d-%d-%d %d:%d", - &unpsize, &packsize, &ratio, &day, - &month, &year, &hour, &min) == 8) { - new = calloc(1, sizeof(ArchiveList_struct)); - if (!new) { - file_num = -1; - break; - } - if (!current) - alist = new; - else - current->next = new; - current = new; - current->item.Name = strdup(fname); - state = PARSE_NAME; - if (!current->item.Name) { - file_num = -1; - break; - } - current->item.PackSize = packsize; - current->item.UnpSize = unpsize; - ++file_num; - continue; - } - strcpy(fname, p); - state = PARSE_PROPS; - } - fclose(rar_pipe); - pid = waitpid(pid, &status, 0); - if (file_num < 0 || (pid == -1 && errno != ECHILD) || - (pid > 0 && status)) { - unrar_exec_freelist(alist); - return -1; - } - if (!alist) - return -1; - *list = alist; - mp_msg(MSGT_GLOBAL, MSGL_V, "UnRAR: list got %d files\n", file_num); - return file_num; -} - -void unrar_exec_freelist(ArchiveList_struct *list) -{ - ArchiveList_struct* tmp; - - while (list) { - tmp = list->next; - free(list->item.Name); - free(list); - list = tmp; - } -} diff --git a/mplayer/unrar_exec.h b/mplayer/unrar_exec.h deleted file mode 100644 index ad67f0e..0000000 --- a/mplayer/unrar_exec.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * List files and extract file from rars by using external executable unrar. - * - * Copyright (C) 2005 Jindrich Makovicka - * Copyright (C) 2007 Ulion - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_UNRAR_EXEC_H -#define MPLAYER_UNRAR_EXEC_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct RAR_archive_entry -{ - char *Name; - unsigned long PackSize; - unsigned long UnpSize; - unsigned long FileCRC; - unsigned long FileTime; - unsigned char UnpVer; - unsigned char Method; - unsigned long FileAttr; -}; - -typedef struct archivelist -{ - struct RAR_archive_entry item; - struct archivelist *next; -} ArchiveList_struct; - -extern char* unrar_executable; - -int unrar_exec_get(unsigned char **output, unsigned long *size, - const char *filename, const char *rarfile); - -int unrar_exec_list(const char *rarfile, ArchiveList_struct **list); - -void unrar_exec_freelist(ArchiveList_struct *list); - -#ifdef __cplusplus -} -#endif - -#endif /* MPLAYER_UNRAR_EXEC_H */ diff --git a/mplayer/vobsub.c b/mplayer/vobsub.c index a6bd324..7cb5189 100644 --- a/mplayer/vobsub.c +++ b/mplayer/vobsub.c @@ -32,13 +32,9 @@ #include #include -//#include "config.h" -#define CONFIG_UNRAR_EXEC 1 // moved from config.h -//#include "mpcommon.h" #include "vobsub.h" #include "spudec.h" #include "mp_msg.h" -#include "unrar_exec.h" // Record the original -vobsubid set by commandline, since vobsub_id will be // overridden if slang match any of vobsub streams. @@ -47,197 +43,14 @@ static int vobsubid = -2; int vobsub_id = 0; // moved from mpcommon.h/mplayer.c /********************************************************************** - * RAR stream handling - * The RAR file must have the same basename as the file to open - **********************************************************************/ -#ifdef CONFIG_UNRAR_EXEC -typedef struct { - FILE *file; - unsigned char *data; - unsigned long size; - unsigned long pos; -} rar_stream_t; - -static rar_stream_t *rar_open(const char *const filename, - const char *const mode) -{ - rar_stream_t *stream; - /* unrar_exec can only read */ - if (strcmp("r", mode) && strcmp("rb", mode)) { - errno = EINVAL; - return NULL; - } - stream = malloc(sizeof(rar_stream_t)); - if (stream == NULL) - return NULL; - /* first try normal access */ - stream->file = fopen(filename, mode); - if (stream->file == NULL) { - char *rar_filename; - const char *p; - int rc; - /* Guess the RAR archive filename */ - rar_filename = NULL; - p = strrchr(filename, '.'); - if (p) { - ptrdiff_t l = p - filename; - rar_filename = malloc(l + 5); - if (rar_filename == NULL) { - free(stream); - return NULL; - } - strncpy(rar_filename, filename, l); - strcpy(rar_filename + l, ".rar"); - } else { - rar_filename = malloc(strlen(filename) + 5); - if (rar_filename == NULL) { - free(stream); - return NULL; - } - strcpy(rar_filename, filename); - strcat(rar_filename, ".rar"); - } - /* get rid of the path if there is any */ - if ((p = strrchr(filename, '/')) == NULL) { - p = filename; - } else { - p++; - } - rc = unrar_exec_get(&stream->data, &stream->size, p, rar_filename); - if (!rc) { - /* There is no matching filename in the archive. However, sometimes - * the files we are looking for have been given arbitrary names in the archive. - * Let's look for a file with an exact match in the extension only. */ - int i, num_files, name_len; - ArchiveList_struct *list, *lp; - num_files = unrar_exec_list(rar_filename, &list); - if (num_files > 0) { - char *demanded_ext; - demanded_ext = strrchr (p, '.'); - if (demanded_ext) { - int demanded_ext_len = strlen (demanded_ext); - for (i = 0, lp = list; i < num_files; i++, lp = lp->next) { - name_len = strlen (lp->item.Name); - if (name_len >= demanded_ext_len && !strcasecmp (lp->item.Name + name_len - demanded_ext_len, demanded_ext)) { - rc = unrar_exec_get(&stream->data, &stream->size, - lp->item.Name, rar_filename); - if (rc) - break; - } - } - } - unrar_exec_freelist(list); - } - if (!rc) { - free(rar_filename); - free(stream); - return NULL; - } - } - - free(rar_filename); - stream->pos = 0; - } - return stream; -} - -static int rar_close(rar_stream_t *stream) -{ - if (stream->file) - return fclose(stream->file); - free(stream->data); - return 0; -} - -static int rar_eof(rar_stream_t *stream) -{ - if (stream->file) - return feof(stream->file); - return stream->pos >= stream->size; -} - -static long rar_tell(rar_stream_t *stream) -{ - if (stream->file) - return ftell(stream->file); - return stream->pos; -} - -static int rar_seek(rar_stream_t *stream, long offset, int whence) -{ - if (stream->file) - return fseek(stream->file, offset, whence); - switch (whence) { - case SEEK_SET: - if (offset < 0) { - errno = EINVAL; - return -1; - } - stream->pos = offset; - break; - case SEEK_CUR: - if (offset < 0 && stream->pos < (unsigned long) -offset) { - errno = EINVAL; - return -1; - } - stream->pos += offset; - break; - case SEEK_END: - if (offset < 0 && stream->size < (unsigned long) -offset) { - errno = EINVAL; - return -1; - } - stream->pos = stream->size + offset; - break; - default: - errno = EINVAL; - return -1; - } - return 0; -} - -static int rar_getc(rar_stream_t *stream) -{ - if (stream->file) - return getc(stream->file); - if (rar_eof(stream)) - return EOF; - return stream->data[stream->pos++]; -} - -static size_t rar_read(void *ptr, size_t size, size_t nmemb, - rar_stream_t *stream) -{ - size_t res; - unsigned long remain; - if (stream->file) - return fread(ptr, size, nmemb, stream->file); - if (rar_eof(stream)) - return 0; - res = size * nmemb; - remain = stream->size - stream->pos; - if (res > remain) - res = remain / size * size; - memcpy(ptr, stream->data + stream->pos, res); - stream->pos += res; - res /= size; - return res; -} - -#else -typedef FILE rar_stream_t; -#define rar_open fopen -#define rar_close fclose -#define rar_eof feof -#define rar_tell ftell -#define rar_seek fseek -#define rar_getc getc -#define rar_read fread -#endif - -/**********************************************************************/ - -static ssize_t vobsub_getline(char **lineptr, size_t *n, rar_stream_t *stream) + * VobSub2SRT does not support RAR-backed subtitle streams. + * The old unRAR handling code has been removed for simplicity + * and to reduce maintenance/memory-safety risk. + * -C +**********************************************************************/ +typedef FILE sub_stream_t; + +static ssize_t vobsub_getline(char **lineptr, size_t *n, sub_stream_t *stream) { size_t res = 0; int c; @@ -246,8 +59,9 @@ static ssize_t vobsub_getline(char **lineptr, size_t *n, rar_stream_t *stream) if (*lineptr) *n = 4096; } else if (*n == 0) { - char *tmp = realloc(*lineptr, 4096); + char *tmp = malloc(4096); if (tmp) { + free(*lineptr); *lineptr = tmp; *n = 4096; } @@ -255,11 +69,12 @@ static ssize_t vobsub_getline(char **lineptr, size_t *n, rar_stream_t *stream) if (*lineptr == NULL || *n == 0) return -1; - for (c = rar_getc(stream); c != EOF; c = rar_getc(stream)) { + for (c = getc(stream); c != EOF; c = getc(stream)) { if (res + 1 >= *n) { char *tmp = realloc(*lineptr, *n * 2); if (tmp == NULL) return -1; + free(*lineptr); *lineptr = tmp; *n *= 2; } @@ -274,13 +89,12 @@ static ssize_t vobsub_getline(char **lineptr, size_t *n, rar_stream_t *stream) (*lineptr)[res] = 0; return res; } - -/********************************************************************** +/*********************************************************************** * MPEG parsing **********************************************************************/ typedef struct { - rar_stream_t *stream; + sub_stream_t *stream; unsigned int pts; int aid; unsigned char *packet; @@ -302,7 +116,7 @@ static mpeg_t *mpeg_open(const char *filename) res->packet_reserve = 0; res->padding_was_here = 1; res->merge = 0; - res->stream = rar_open(filename, "rb"); + res->stream = fopen(filename, "rb"); err = res->stream == NULL; if (err) perror("fopen Vobsub file failed"); @@ -317,18 +131,18 @@ static void mpeg_free(mpeg_t *mpeg) if (mpeg->packet) free(mpeg->packet); if (mpeg->stream) - rar_close(mpeg->stream); + fclose(mpeg->stream); free(mpeg); } static int mpeg_eof(mpeg_t *mpeg) { - return rar_eof(mpeg->stream); + return feof(mpeg->stream); } static off_t mpeg_tell(mpeg_t *mpeg) { - return rar_tell(mpeg->stream); + return ftell(mpeg->stream); } static int mpeg_run(mpeg_t *mpeg) @@ -341,10 +155,10 @@ static int mpeg_run(mpeg_t *mpeg) mpeg->aid = -1; mpeg->packet_size = 0; - if (rar_read(buf, 4, 1, mpeg->stream) != 1) + if (fread(buf, 4, 1, mpeg->stream) != 1) return -1; while (memcmp(buf, wanted, sizeof(wanted)) != 0) { - c = rar_getc(mpeg->stream); + c = getc(mpeg->stream); if (c < 0) return -1; memmove(buf, buf + 1, 3); @@ -354,7 +168,7 @@ static int mpeg_run(mpeg_t *mpeg) case 0xb9: /* System End Code */ break; case 0xba: /* Packet start code */ - c = rar_getc(mpeg->stream); + c = getc(mpeg->stream); if (c < 0) return -1; if ((c & 0xc0) == 0x40) @@ -366,29 +180,29 @@ static int mpeg_run(mpeg_t *mpeg) return -1; } if (version == 4) { - if (rar_seek(mpeg->stream, 9, SEEK_CUR)) - return -1; - } else if (version == 2) { - if (rar_seek(mpeg->stream, 7, SEEK_CUR)) - return -1; - } else - abort(); - if (!mpeg->padding_was_here) - mpeg->merge = 1; - break; + if (fseek(mpeg->stream, 9, SEEK_CUR)) + return -1; + } else if (version == 2) { + if (fseek(mpeg->stream, 7, SEEK_CUR)) + return -1; + } else + abort(); + if (!mpeg->padding_was_here) + mpeg->merge = 1; + break; case 0xbd: /* packet */ - if (rar_read(buf, 2, 1, mpeg->stream) != 1) + if (fread(buf, 2, 1, mpeg->stream) != 1) return -1; mpeg->padding_was_here = 0; len = buf[0] << 8 | buf[1]; idx = mpeg_tell(mpeg); - c = rar_getc(mpeg->stream); + c = getc(mpeg->stream); if (c < 0) return -1; if ((c & 0xC0) == 0x40) { /* skip STD scale & size */ - if (rar_getc(mpeg->stream) < 0) + if (getc(mpeg->stream) < 0) return -1; - c = rar_getc(mpeg->stream); + c = getc(mpeg->stream); if (c < 0) return -1; } @@ -400,11 +214,11 @@ static int mpeg_run(mpeg_t *mpeg) abort(); } else if ((c & 0xc0) == 0x80) { /* System-2 (.VOB) stream */ unsigned int pts_flags, hdrlen, dataidx; - c = rar_getc(mpeg->stream); + c = getc(mpeg->stream); if (c < 0) return -1; pts_flags = c; - c = rar_getc(mpeg->stream); + c = getc(mpeg->stream); if (c < 0) return -1; hdrlen = c; @@ -415,7 +229,7 @@ static int mpeg_run(mpeg_t *mpeg) return -1; } if ((pts_flags & 0xc0) == 0x80) { - if (rar_read(buf, 5, 1, mpeg->stream) != 1) + if (fread(buf, 5, 1, mpeg->stream) != 1) return -1; if (!(((buf[0] & 0xf0) == 0x20) && (buf[0] & 1) && (buf[2] & 1) && (buf[4] & 1))) { mp_msg(MSGT_VOBSUB, MSGL_ERR, "vobsub PTS error: 0x%02x %02x%02x %02x%02x \n", @@ -428,8 +242,8 @@ static int mpeg_run(mpeg_t *mpeg) /* what's this? */ /* abort(); */ } - rar_seek(mpeg->stream, dataidx, SEEK_SET); - mpeg->aid = rar_getc(mpeg->stream); + fseek(mpeg->stream, dataidx, SEEK_SET); + mpeg->aid = getc(mpeg->stream); if (mpeg->aid < 0) { mp_msg(MSGT_VOBSUB, MSGL_ERR, "Bogus aid %d\n", mpeg->aid); return -1; @@ -448,7 +262,7 @@ static int mpeg_run(mpeg_t *mpeg) mpeg->packet_size = 0; return -1; } - if (rar_read(mpeg->packet, mpeg->packet_size, 1, mpeg->stream) != 1) { + if (fread(mpeg->packet, mpeg->packet_size, 1, mpeg->stream) != 1) { mp_msg(MSGT_VOBSUB, MSGL_ERR, "fread failure"); mpeg->packet_size = 0; return -1; @@ -457,20 +271,20 @@ static int mpeg_run(mpeg_t *mpeg) } break; case 0xbe: /* Padding */ - if (rar_read(buf, 2, 1, mpeg->stream) != 1) + if (fread(buf, 2, 1, mpeg->stream) != 1) return -1; len = buf[0] << 8 | buf[1]; - if (len > 0 && rar_seek(mpeg->stream, len, SEEK_CUR)) + if (len > 0 && fseek(mpeg->stream, len, SEEK_CUR)) return -1; mpeg->padding_was_here = 1; break; default: if (0xc0 <= buf[3] && buf[3] < 0xf0) { /* MPEG audio or video */ - if (rar_read(buf, 2, 1, mpeg->stream) != 1) + if (fread(buf, 2, 1, mpeg->stream) != 1) return -1; len = buf[0] << 8 | buf[1]; - if (len > 0 && rar_seek(mpeg->stream, len, SEEK_CUR)) + if (len > 0 && fseek(mpeg->stream, len, SEEK_CUR)) return -1; } else { mp_msg(MSGT_VOBSUB, MSGL_ERR, "unknown header 0x%02X%02X%02X%02X\n", @@ -530,6 +344,8 @@ static void packet_queue_destroy(packet_queue_t *queue) packet_destroy(queue->packets + queue->packets_size); free(queue->packets); } + if (queue->id) + free(queue->id); return; } @@ -642,6 +458,7 @@ static int vobsub_add_id(vobsub_t *vob, const char *id, size_t idlen, vob->spu_streams[index].id = malloc(idlen + 1); if (vob->spu_streams[index].id == NULL) { mp_msg(MSGT_VOBSUB, MSGL_FATAL, "vobsub_add_id: malloc failure"); + free(vob->spu_streams[index].id); return -1; } vob->spu_streams[index].id[idlen] = 0; @@ -820,7 +637,7 @@ static int vobsub_set_lang(const char *line) return 0; } -static int vobsub_parse_one_line(vobsub_t *vob, rar_stream_t *fd, +static int vobsub_parse_one_line(vobsub_t *vob, sub_stream_t *fd, unsigned char **extradata, unsigned int *extradata_len) { @@ -871,7 +688,7 @@ static int vobsub_parse_one_line(vobsub_t *vob, rar_stream_t *fd, break; } while (1); if (line) - free(line); + free(line); return res; } @@ -881,7 +698,7 @@ int vobsub_parse_ifo(void* this, const char *const name, unsigned int *palette, { vobsub_t *vob = this; int res = -1; - rar_stream_t *fd = rar_open(name, "rb"); + sub_stream_t *fd = fopen(name, "rb"); if (fd == NULL) { //if (force) //mp_msg(MSGT_VOBSUB, MSGL_WARN, "VobSub: Can't open IFO file\n"); @@ -889,7 +706,7 @@ int vobsub_parse_ifo(void* this, const char *const name, unsigned int *palette, // parse IFO header unsigned char block[0x800]; const char *const ifo_magic = "DVDVIDEO-VTS"; - if (rar_read(block, sizeof(block), 1, fd) != 1) { + if (fread(block, sizeof(block), 1, fd) != 1) { if (force) mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't read IFO header\n"); } else if (memcmp(block, ifo_magic, strlen(ifo_magic) + 1)) @@ -924,8 +741,8 @@ int vobsub_parse_ifo(void* this, const char *const name, unsigned int *palette, langid[1] = tmp[1]; langid[2] = 0; } - if (rar_seek(fd, pgci_sector * sizeof(block), SEEK_SET) - || rar_read(block, sizeof(block), 1, fd) != 1) + if (fseek(fd, pgci_sector * sizeof(block), SEEK_SET) + || fread(block, sizeof(block), 1, fd) != 1) mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't read IFO PGCI\n"); else { unsigned long idx; @@ -940,7 +757,7 @@ int vobsub_parse_ifo(void* this, const char *const name, unsigned int *palette, res = 0; } } - rar_close(fd); + fclose(fd); } return res; } @@ -959,7 +776,7 @@ void *vobsub_open(const char *const name, const char *const ifo, char *buf; buf = malloc(strlen(name) + 5); if (buf) { - rar_stream_t *fd; + sub_stream_t *fd; mpeg_t *mpg; /* read in the info file */ if (!ifo) { @@ -971,22 +788,30 @@ void *vobsub_open(const char *const name, const char *const ifo, /* read in the index */ strcpy(buf, name); strcat(buf, ".idx"); - fd = rar_open(buf, "rb"); + fd = fopen(buf, "rb"); if (fd == NULL) { if (force) mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't open IDX file\n"); else { free(buf); + free(vob); + if (spu && *spu) { + spudec_free(*spu); + *spu = NULL; + vob = NULL; + } free(vob); return NULL; } } else { while (vobsub_parse_one_line(vob, fd, &extradata, &extradata_len) >= 0) - /* NOOP */ ; - rar_close(fd); + /* NO-OP */; + fclose(fd); } if (spu) - *spu = spudec_new_scaled(vob->palette, vob->orig_frame_width, vob->orig_frame_height, extradata, extradata_len, y_threshold); + *spu = spudec_new_scaled(vob->palette, vob->orig_frame_width, + vob->orig_frame_height, extradata, extradata_len, + y_threshold); if (extradata) free(extradata); @@ -999,6 +824,11 @@ void *vobsub_open(const char *const name, const char *const ifo, mp_msg(MSGT_VOBSUB, MSGL_ERR, "VobSub: Can't open SUB file\n"); else { free(buf); + if (spu && *spu) { + spudec_free(*spu); + *spu = NULL; + vob = NULL; + } free(vob); return NULL; } @@ -1057,7 +887,7 @@ void *vobsub_open(const char *const name, const char *const ifo, vob->spu_streams_current = vob->spu_streams_size; while (vob->spu_streams_current-- > 0) { vob->spu_streams[vob->spu_streams_current].current_index = 0; - if (vobsubid == vob->spu_streams_current || + if (vobsubid == (int)vob->spu_streams_current || vob->spu_streams[vob->spu_streams_current].packets_size > 0) ++vob->spu_valid_streams_size; } @@ -1095,11 +925,11 @@ char *vobsub_get_id(void *vobhandle, unsigned int index) int vobsub_get_id_by_index(void *vobhandle, unsigned int index) { vobsub_t *vob = vobhandle; - int i, j; + unsigned int i, j; if (vob == NULL) return -1; for (i = 0, j = 0; i < vob->spu_streams_size; ++i) - if (i == vobsubid || vob->spu_streams[i].packets_size > 0) { + if ((int)i == vobsubid || vob->spu_streams[i].packets_size > 0) { if (j == index) return i; ++j; @@ -1111,7 +941,7 @@ int vobsub_get_index_by_id(void *vobhandle, int id) { vobsub_t *vob = vobhandle; int i, j; - if (vob == NULL || id < 0 || id >= vob->spu_streams_size) + if (vob == NULL || id < 0 || (unsigned int)id >= vob->spu_streams_size) return -1; if (id != vobsubid && !vob->spu_streams[id].packets_size) return -1; @@ -1123,7 +953,7 @@ int vobsub_get_index_by_id(void *vobhandle, int id) int vobsub_set_from_lang(void *vobhandle, char const *lang) { - int i; + unsigned int i; vobsub_t *vob= vobhandle; while (lang && strlen(lang) >= 2) { for (i = 0; i < vob->spu_streams_size; i++) @@ -1149,7 +979,7 @@ static void vobsub_queue_reseek(packet_queue_t *queue, unsigned int pts100) && (queue->packets[queue->current_index].pts100 == UINT_MAX || queue->packets[queue->current_index].pts100 > pts100)) { // possible pts seek previous, try to check it. - int i = 1; + unsigned int i = 1; while (queue->current_index >= i && queue->packets[queue->current_index-i].pts100 == UINT_MAX) ++i; @@ -1238,220 +1068,3 @@ void vobsub_reset(void *vobhandle) vob->spu_streams[n].current_index = 0; } } - -#if 0 // R: no output needed -/********************************************************************** - * Vobsub output - **********************************************************************/ - -typedef struct { - FILE *fsub; - FILE *fidx; - unsigned int aid; -} vobsub_out_t; - -static void create_idx(vobsub_out_t *me, const unsigned int *palette, - unsigned int orig_width, unsigned int orig_height) -{ - int i; - fprintf(me->fidx, - "# VobSub index file, v7 (do not modify this line!)\n" - "#\n" - "# Generated by %s\n" - "# See for more information about MPlayer\n" - "# See for more information about Vobsub\n" - "#\n" - "size: %ux%u\n", - mplayer_version, orig_width, orig_height); - if (palette) { - fputs("palette:", me->fidx); - for (i = 0; i < 16; ++i) { - const double y = palette[i] >> 16 & 0xff, - u = (palette[i] >> 8 & 0xff) - 128.0, - v = (palette[i] & 0xff) - 128.0; - if (i) - putc(',', me->fidx); - fprintf(me->fidx, " %02x%02x%02x", - av_clip_uint8(y + 1.4022 * u), - av_clip_uint8(y - 0.3456 * u - 0.7145 * v), - av_clip_uint8(y + 1.7710 * v)); - } - putc('\n', me->fidx); - } - - fprintf(me->fidx, "# ON: displays only forced subtitles, OFF: shows everything\n" - "forced subs: OFF\n"); -} - -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) -{ - vobsub_out_t *result = NULL; - char *filename; - filename = malloc(strlen(basename) + 5); - if (filename) { - result = malloc(sizeof(vobsub_out_t)); - if (result) { - result->aid = index; - strcpy(filename, basename); - strcat(filename, ".sub"); - result->fsub = fopen(filename, "ab"); - if (result->fsub == NULL) - perror("Error: vobsub_out_open subtitle file open failed"); - strcpy(filename, basename); - strcat(filename, ".idx"); - result->fidx = fopen(filename, "ab"); - if (result->fidx) { - if (ftell(result->fidx) == 0) { - create_idx(result, palette, orig_width, orig_height); - /* Make the selected language the default language */ - fprintf(result->fidx, "\n# Language index in use\nlangidx: %u\n", index); - } - fprintf(result->fidx, "\nid: %s, index: %u\n", id ? id : "xx", index); - /* So that we can check the file now */ - fflush(result->fidx); - } else - perror("Error: vobsub_out_open index file open failed"); - free(filename); - } - } - return result; -} - -void vobsub_out_close(void *me) -{ - vobsub_out_t *vob = me; - if (vob->fidx) - fclose(vob->fidx); - if (vob->fsub) - fclose(vob->fsub); - free(vob); -} - -void vobsub_out_output(void *me, const unsigned char *packet, - int len, double pts) -{ - static double last_pts; - static int last_pts_set = 0; - vobsub_out_t *vob = me; - if (vob->fsub) { - /* Windows' Vobsub require that every packet is exactly 2kB long */ - unsigned char buffer[2048]; - unsigned char *p; - int remain = 2048; - /* Do not output twice a line with the same timestamp, this - breaks Windows' Vobsub */ - if (vob->fidx && (!last_pts_set || last_pts != pts)) { - static unsigned int last_h = 9999, last_m = 9999, last_s = 9999, last_ms = 9999; - unsigned int h, m, ms; - double s; - s = pts; - h = s / 3600; - s -= h * 3600; - m = s / 60; - s -= m * 60; - ms = (s - (unsigned int) s) * 1000; - if (ms >= 1000) /* prevent overflows or bad float stuff */ - ms = 0; - if (h != last_h || m != last_m || (unsigned int) s != last_s || ms != last_ms) { - fprintf(vob->fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: %09lx\n", - h, m, (unsigned int) s, ms, ftell(vob->fsub)); - last_h = h; - last_m = m; - last_s = (unsigned int) s; - last_ms = ms; - } - } - last_pts = pts; - last_pts_set = 1; - - /* Packet start code: Windows' Vobsub needs this */ - p = buffer; - *p++ = 0; /* 0x00 */ - *p++ = 0; - *p++ = 1; - *p++ = 0xba; - *p++ = 0x40; - memset(p, 0, 9); - p += 9; - { /* Packet */ - static unsigned char last_pts[5] = { 0, 0, 0, 0, 0}; - unsigned char now_pts[5]; - int pts_len, pad_len, datalen = len; - pts *= 90000; - now_pts[0] = 0x21 | (((unsigned long)pts >> 29) & 0x0e); - now_pts[1] = ((unsigned long)pts >> 22) & 0xff; - now_pts[2] = 0x01 | (((unsigned long)pts >> 14) & 0xfe); - now_pts[3] = ((unsigned long)pts >> 7) & 0xff; - now_pts[4] = 0x01 | (((unsigned long)pts << 1) & 0xfe); - pts_len = memcmp(last_pts, now_pts, sizeof(now_pts)) ? sizeof(now_pts) : 0; - memcpy(last_pts, now_pts, sizeof(now_pts)); - - datalen += 3; /* Version, PTS_flags, pts_len */ - datalen += pts_len; - datalen += 1; /* AID */ - pad_len = 2048 - (p - buffer) - 4 /* MPEG ID */ - 2 /* payload len */ - datalen; - /* XXX - Go figure what should go here! In any case the - packet has to be completely filled. If I can fill it - with padding (0x000001be) latter I'll do that. But if - there is only room for 6 bytes then I can not write a - padding packet. So I add some padding in the PTS - field. This looks like a dirty kludge. Oh well... */ - if (pad_len < 0) { - /* Packet is too big. Let's try omitting the PTS field */ - datalen -= pts_len; - pts_len = 0; - pad_len = 0; - } else if (pad_len > 6) - pad_len = 0; - datalen += pad_len; - - *p++ = 0; /* 0x0e */ - *p++ = 0; - *p++ = 1; - *p++ = 0xbd; - - *p++ = (datalen >> 8) & 0xff; /* length of payload */ - *p++ = datalen & 0xff; - *p++ = 0x80; /* System-2 (.VOB) stream */ - *p++ = pts_len ? 0x80 : 0x00; /* pts_flags */ - *p++ = pts_len + pad_len; - memcpy(p, now_pts, pts_len); - p += pts_len; - memset(p, 0, pad_len); - p += pad_len; - } - *p++ = 0x20 | vob->aid; /* aid */ - if (fwrite(buffer, p - buffer, 1, vob->fsub) != 1 - || fwrite(packet, len, 1, vob->fsub) != 1) - perror("ERROR: vobsub write failed"); - else - remain -= p - buffer + len; - - /* Padding */ - if (remain >= 6) { - p = buffer; - *p++ = 0x00; - *p++ = 0x00; - *p++ = 0x01; - *p++ = 0xbe; - *p++ = (remain - 6) >> 8; - *p++ = (remain - 6) & 0xff; - /* for better compression, blank this */ - memset(buffer + 6, 0, remain - (p - buffer)); - if (fwrite(buffer, remain, 1, vob->fsub) != 1) - perror("ERROR: vobsub padding write failed"); - } else if (remain > 0) { - /* I don't know what to output. But anyway the block - needs to be 2KB big */ - memset(buffer, 0, remain); - if (fwrite(buffer, remain, 1, vob->fsub) != 1) - perror("ERROR: vobsub blank padding write failed"); - } else if (remain < 0) - fprintf(stderr, - "\nERROR: wrong thing happened...\n" - " I wrote a %i data bytes spu packet and that's too long\n", len); - } -} -#endif diff --git a/mplayer/vobsub.h b/mplayer/vobsub.h index 0a32ae7..300ce57 100644 --- a/mplayer/vobsub.h +++ b/mplayer/vobsub.h @@ -44,11 +44,7 @@ unsigned int vobsub_palette_to_yuv(unsigned int pal); /// Convert rgb value to yuv. unsigned int vobsub_rgb_to_yuv(unsigned int rgb); -#if 0 // R: no output needed -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); -void vobsub_out_output(void *me, const unsigned char *packet, int len, double pts); -void vobsub_out_close(void *me); -#endif +//C: output removed int vobsub_set_from_lang(void *vobhandle, char const *lang); // R: changed lang from unsigned char* void vobsub_seek(void * vobhandle, float pts); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9eac1ad..dabe0c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,6 @@ if(BUILD_STATIC) LINK_SEARCH_END_STATIC ON LINK_FLAGS -static) endif() -target_link_libraries(vobsub2srt mplayer ${Libavutil_LIBRARIES} ${Tesseract_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(vobsub2srt PNG::PNG mplayer ${Libavutil_LIBRARIES} ${Leptonica_LIBRARIES} ${Tesseract_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS vobsub2srt RUNTIME DESTINATION ${INSTALL_EXECUTABLES_PATH}) diff --git a/src/cmd_options.c++ b/src/cmd_options.c++ index 3b2df59..dbacaaa 100644 --- a/src/cmd_options.c++ +++ b/src/cmd_options.c++ @@ -19,6 +19,7 @@ #include "cmd_options.h++" #include +#include #include #include #include @@ -165,17 +166,49 @@ bool cmd_options::parse_cmd(int argc, char **argv) const { } void cmd_options::help(char const *progname) const { + cerr << "Usage:\n" + << " " << progname << " [options]"; + for(std::vector::const_iterator i = pimpl->unnamed_args.begin(); i != pimpl->unnamed_args.end(); ++i) { + cerr << " <" << i->name << '>'; + } + cerr << "\n\n"; + /* cerr << "usage: " << progname; for(std::vector