From: Chris Tallon Date: Mon, 14 Mar 2022 21:25:52 +0000 (+0000) Subject: Switch to cmake X-Git-Url: https://git.vomp.tv/gitweb/?a=commitdiff_plain;h=0ad4577992e1245e1624fde3c525ca54ba6594f6;p=vompclient.git Switch to cmake --- diff --git a/.gitignore b/.gitignore index 26a69ca..0974245 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,4 @@ -#do not include make output -*.o -vompclient -deps -#ignore target-* directory links -target-* *~ -#ignore eclipse project files -.project -.cproject .#* config.json +build diff --git a/GNUmakefile b/GNUmakefile deleted file mode 100644 index 2d55693..0000000 --- a/GNUmakefile +++ /dev/null @@ -1,149 +0,0 @@ -# Switches for this Makefile: - -# VERBOSE - set to 1 to show all commands -# SKIPDEPS - Skip regeneration of dependencies file - -include objects.mk - -vomp_platform=$(shell ./select-platform) -# vomp_platform variable sets up the build on different platforms -# valid platforms are: -# raspberry - native compile for & on Raspberry Pi -# crossraspberry - cross compile for Raspberry Pi -# Override auto select here: -# vomp_platform= - -$(info Build system selected: $(vomp_platform)) - -ALL_THE_WARNINGS_OFF=0 - -CROSSROOT=/pi-root - -# uncomment the line below if you want to build vomp application without a reboot option, automatically set for windows! -#VOMP_OPTIONS+= -DVOMP_HAS_EXIT - -ifndef VERBOSE -Q = @ -endif - -# Pictures for linux builds -PICTURES = -Wl,--format=binary -PICTURES += -Wl,other/vdrhires.png -PICTURES += -Wl,other/wallpaper720p.jpg -PICTURES += -Wl,other/properties.png -PICTURES += -Wl,other/radio.png -PICTURES += -Wl,other/timers.png -PICTURES += -Wl,other/tv.png -PICTURES += -Wl,other/recordings.png -PICTURES += -Wl,other/restart.png -PICTURES += -Wl,other/hd1080i.png -PICTURES += -Wl,other/hd720p.png -PICTURES += -Wl,other/sd576i.png -PICTURES += -Wl,other/txtoff.png -PICTURES += -Wl,other/txton.png -PICTURES += -Wl,other/dolbyoff.png -PICTURES += -Wl,other/dolbyon.png -PICTURES += -Wl,other/recording.png -PICTURES += -Wl,other/recfolder.png -PICTURES += -Wl,other/defposter.png -PICTURES += -Wl,--format=default - -DEFINES=-D_GNU_SOURCE - - -ifeq ($(vomp_platform),raspberry) -$(info Raspberry Pi native compiler) -CC=gcc -STRIP=strip -CXX=g++ -LD=g++ - -#CC=clang-9 -#STRIP=strip -#CXX=clang++-9 -#LD=clang++-9 - -LDFLAGS = $(PICTURES) -#-fuse-ld=gold - -DEFINES += -DIPV4 -DIPV6 -LIBPATHS = -L/opt/vc/lib -L/usr/lib/arm-linux-gnueabihf -LIBS = -lpthread -lrt -lbrcmEGL -lbrcmOpenVG -lopenmaxil -lbcm_host -lavformat -lavcodec \ - -lavutil -lswresample -ljsoncpp -lfmt -ldl -lfontconfig -lfreetype -lMagick++-6.Q16 -OBJECTS = $(OBJ_COMMON) $(OBJ_RASPBERRY) -INCLUDES = -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/usr/include/freetype2 -I/usr/include/ImageMagick -I/usr/include/ImageMagick-6 -I/usr/include/arm-linux-gnueabihf/ImageMagick-6 -DEFINES += -DVOMP_PLATFORM_RASPBERRY -CXXFLAGS_EXTRA = -Wno-psabi -endif - - - -# Debian 10 x64 -# apt install g++-arm-linux-gnueabihf -# Set vomp_platform=crossraspberry above -ifeq ($(vomp_platform),crossraspberry) -SYSROOT= --sysroot=$(CROSSROOT) -DEFINES += -DIPV4 -DIPV6 -CROSS_PREFIX=arm-linux-gnueabihf- -CC=$(CROSS_PREFIX)gcc -STRIP=$(CROSS_PREFIX)strip -CXX=$(CROSS_PREFIX)g++ -LD=$(CROSS_PREFIX)g++ - -LDFLAGS = -Wall $(PICTURES) $(SYSROOT) \ - -Wl,-rpath-link,$(CROSSROOT)/opt/vc/lib -Wl,-rpath-link,$(CROSSROOT)/usr/lib/arm-linux-gnueabihf -LIBPATHS = -L=/opt/vc/lib -L=/usr/lib/arm-linux-gnueabihf -LIBS = -lpthread -lstdc++ -lrt -lbrcmEGL -lbrcmOpenVG -lopenmaxil -lbcm_host -lavformat -lavcodec \ - -lfmt -lavutil -lswresample -lm -ldl -lfontconfig -lfreetype -lMagick++-6.Q16 -lMagickWand-6.Q16 \ - -lMagickCore-6.Q16 -ljsoncpp -OBJECTS = $(OBJ_COMMON) $(OBJ_RASPBERRY) -INCLUDES = -isystem=/usr/include/arm-linux-gnueabihf -isystem=/opt/vc/include -isystem=/usr/include/freetype2 -isystem=/usr/include/arm-linux-gnueabihf/ImageMagick-6 -isystem=/usr/include/ImageMagick-6 -DEFINES += -DVOMP_PLATFORM_RASPBERRY -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -CXXFLAGS_EXTRA = $(SYSROOT) -Wno-psabi -mtune=cortex-a7 -mfloat-abi=hard -fopenmp -endif - - -ifeq ($(ALL_THE_WARNINGS_OFF),1) -CXXFLAGS_DEV = $(DEFINES) -DDEV -g -O0 -std=c++14 -Wno-deprecated $(CXXFLAGS_EXTRA) $(INCLUDES) -else -CXXFLAGS_DEV = $(DEFINES) -DDEV -g -O0 -Wall -Wextra -Wshadow -Werror=return-type -Wmissing-format-attribute -Wdisabled-optimization -Wmissing-declarations -Wmissing-noreturn -Winit-self -Woverloaded-virtual -Wold-style-cast -Wconversion -std=c++14 $(CXXFLAGS_EXTRA) $(INCLUDES) -endif - -CXXFLAGS_REL = $(DEFINES) -O3 -std=c++14 $(CXXFLAGS_EXTRA) $(INCLUDES) - -.PHONY: clean fresh all install strip - -default: dev -fresh: clean default - -%.o: %.cc - @echo CC $@ - $(Q)$(CXX) $(CXXFLAGS) -c -o $@ $< - -vompclient: $(OBJECTS) - @echo LD vompclient - $(Q)$(LD) $(LDFLAGS) $(LIBPATHS) -o vompclient $(OBJECTS) $(LIBS) - @echo Done - -strip: - @echo STRIP vompclient - $(Q)$(STRIP) vompclient - -dev: CXXFLAGS := $(CXXFLAGS_DEV) -dev: vompclient - -release: CXXFLAGS := $(CXXFLAGS_REL) -release: vompclient strip - -clean: - rm -f *.o deps vompclient *~ fonts/*.o fonts/*~ teletxt/*.o - -ifndef SKIPDEPS -deps: GNUmakefile - @echo "DEPS" - $(Q)$(CC) -MM $(SYSROOT) $(INCLUDES) $(OBJECTS:%.o=%.cc) > deps -endif - -ifneq ($(MAKECMDGOALS),clean) -include deps -endif diff --git a/Makefile.nmake b/Makefile.nmake deleted file mode 100644 index ed6e9ee..0000000 --- a/Makefile.nmake +++ /dev/null @@ -1,66 +0,0 @@ -CXXFLAGS_DEV = -g -O0 -Wall -Woverloaded-virtual -Wshadow -Werror -DDEV -D_GNU_SOURCE $(INCLUDES) -CXXFLAGS_REL = /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "NEW_DEMUXER" /nologo /EHsc /MD /GS /W3 /c /TP -LDFLAGS = /INCREMENTAL:NO /NOLOGO /NODEFAULTLIB /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /LIBPATH:"$(DXSDK_DIR)\Lib\x86" - -LIBS = Msvcrt.lib Ws2_32.lib shlwapi.lib d3d9.lib Iphlpapi.lib Strmiids.lib Mfuuid.lib winmm.lib MSVCPRT.lib kernel32.lib user32.lib gdi32.lib ole32.lib uuid.lib oleaut32.lib - -LIBSLEGACY = gdiplus.lib - -LIBSCURRENT = d3d10_1.lib d2d1.lib dwrite.lib windowscodecs.lib - -CROSSLIBS = - -!include "objects.mk" - -OBJECTS = $(OBJ_COMMON) $(OBJ_WINDOWS) - -#.PHONY: clean fresh all install strip - -default: release #dev - -!ifdef LEGACY -release:: -CXXFLAGS= /D "WINDOWS_LEGACY" $(CXXFLAGS_REL) -OBJECTS = $(OBJECTS) $(OBJ_WINLEGACY) -LIBS = $(LIBS) $(LIBSLEGACY) -release:: vompclient-legacy.exe - - -vompclient-legacy.exe: $(OBJECTS) vompwin.res - link $(LDFLAGS) /OUT:"vompclient-legacy.exe" $(LIBS) $(OBJECTS) vompwin.res -!else - - -release:: -CXXFLAGS= $(CXXFLAGS_REL) -OBJECTS = $(OBJECTS) $(OBJ_WINCURRENT) -LIBS = $(LIBS) $(LIBSCURRENT) -release:: vompclient.exe - -vompclient.exe: $(OBJECTS) vompwin.res - link $(LDFLAGS) /OUT:"vompclient.exe" $(LIBS) $(OBJECTS) vompwin.res - -!endif - - - -$(OBJECTS): $*.cc - $(CXX) $(CXXFLAGS) /Fo$*.o $*.cc - -!ifdef LEGACY -vompwin.res:vompwin.rc - $(RC) /d WINDOWS_LEGACY /fo"vompwin.res" "vompwin.rc" -!else -vompwin.res:vompwin.rc - $(RC) /fo"vompwin.res" "vompwin.rc" -!endif - -clean: - del *.o -!ifdef LEGACY - del vompclient-legacy.exe -!else - del vompclient.exe -!endif - del fonts\*.o - diff --git a/abstractoption.cc b/abstractoption.cc deleted file mode 100644 index 6e9d13a..0000000 --- a/abstractoption.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2007-2008 Marten Richter - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "abstractoption.h" -#include "vdr.h" -#include "option.h" - -/* -bool AbstractOption::loadOptionsFromServer(VDR* vdr) -{ - return true; -} - -bool AbstractOption::saveOptionstoServer() -{ - return true; -} - -bool AbstractOption::addOptionPagesToWTB(WTabBar *wtb) -{ - return true; -} - -bool AbstractOption::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane) -{ - return true; -} - -bool AbstractOption::handleOptionChanges(Option* option) -{ - return false; -}*/ - diff --git a/abstractoption.h b/abstractoption.h deleted file mode 100644 index 7933300..0000000 --- a/abstractoption.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright 2007-2008 Marten Richter - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef ABSTRACT_OPTION_H -#define ABSTRACT_OPTION_H - -#include "defines.h" -#include "option.h" - -class WTabBar; -class VDR; -class WOptionPane; - -class AbstractOption -{ - public: - // inline definition allows plugins architecture for audio video - virtual bool loadOptionsFromServer(VDR*) { return true; }; - virtual bool saveOptionstoServer() { return true; }; - virtual bool addOptionPagesToWTB(WTabBar*) { return true; }; - virtual bool addOptionsToPanes(int /* panenumber */, Options*, WOptionPane*) { return true; }; - virtual bool handleOptionChanges(Option*) { return false; }; -}; - -#endif diff --git a/afeed.cc b/afeed.cc deleted file mode 100644 index 6493c76..0000000 --- a/afeed.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright 2004-2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#include "log.h" -#include "demuxer.h" -#include "callback.h" -#include "util.h" - -#include "afeed.h" - -AFeed::AFeed(Callback* tcb) -: cb(*tcb) -{ - audioEnabled = 1; -} - -void AFeed::disable() -{ - audioEnabled = 0; -} - -void AFeed::enable() -{ - audioEnabled = 1; -} - -void AFeed::start() -{ - audioEnabled = 1; - - threadStartProtect.lock(); - feedThread = std::thread( [this] - { - threadStartProtect.lock(); - threadStartProtect.unlock(); - threadMethod(); - }); - threadStartProtect.unlock(); -} - -void AFeed::stop() -{ - LogNT::getInstance()->debug("AFeed", "Stop1"); - if (!feedThread.joinable()) return; - stopThread = true; - feedThread.join(); - stopThread = false; - LogNT::getInstance()->debug("AFeed", "Stop2"); -} - -void AFeed::threadMethod() -{ - bool alen; - - while(1) - { - if (stopThread) return; - - if (audioEnabled) - { - bool newdata=false; - alen = Demuxer::getInstance()->writeAudio(&newdata); - - if (newdata) cb.call(this); - if (alen) - { - //LogNT::getInstance()->debug("AFeed", "written"); - cb.call(this); - } - else - { - //MILLISLEEP(100); - MILLISLEEP(5); //Performance Issue Marten - } - } - else - { - Demuxer::getInstance()->flushAudio(); - //LogNT::getInstance()->debug("AFeed", "No data delay"); - //MILLISLEEP(100); - MILLISLEEP(5); //Performance Issue - } - } -} - diff --git a/afeed.h b/afeed.h deleted file mode 100644 index d2ea550..0000000 --- a/afeed.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2004-2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef AFEED_H -#define AFEED_H - -#include -#include - -class Callback; - -class AFeed -{ - public: - AFeed(Callback* tcb); - - void start(); - void stop(); - void enable(); - void disable(); - - private: - std::thread feedThread; - std::mutex threadStartProtect; - void threadMethod(); - bool stopThread{}; - - int audioEnabled; - bool callbacksend; - Callback& cb; -}; - -#endif diff --git a/audio.cc b/audio.cc deleted file mode 100644 index 0904050..0000000 --- a/audio.cc +++ /dev/null @@ -1,119 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "audio.h" - -#include "log.h" - -Audio* Audio::instance = NULL; - -Audio::Audio() -{ - if (instance) return; - instance = this; - memset(&Aoffset, 0, sizeof(Aoffset)); - userMute = 0; - systemMute = 0; -} - -Audio::~Audio() -{ - instance = NULL; -} - -Audio* Audio::getInstance() -{ - return instance; -} -/* -void Audio::setInstance(Audio* inst) -{ - instance=inst; -}*/ - -int Audio::volumeUp() -{ - if (!initted) return 0; - if (userMute) toggleUserMute(); - if (volume == 20) return volume; - volume++; - setVolume(volume); - return volume; -} - -int Audio::volumeDown() -{ - if (!initted) return 0; - if (userMute) toggleUserMute(); - if (volume == 0) return 0; - volume--; - setVolume(volume); - return volume; -} - -int Audio::getVolume() -{ - if (!initted) return 0; - return volume; -} - -int Audio::toggleUserMute() -{ - if (!initted) return 0; - - if (userMute) - { - userMute = 0; - } - else - { - userMute = 1; - } - - doMuting(); - - return userMute; -} - -int Audio::systemMuteOn() -{ - systemMute = 1; - return doMuting(); -} - -int Audio::systemMuteOff() -{ - systemMute = 0; - return doMuting(); -} - -int Audio::doMuting() -{ - LogNT::getInstance()->debug("Audio", "doMuting: user={} sys={}", userMute, systemMute); - - if (userMute || systemMute) - { - return mute(); - } - else - { - return unMute(); - } -} diff --git a/audio.h b/audio.h deleted file mode 100644 index 4a3342b..0000000 --- a/audio.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef AUDIO_H -#define AUDIO_H - -#include -#include "defines.h" -#include "draintarget.h" -#include "abstractoption.h" - -typedef struct -{ - unsigned char frontleft; - unsigned char frontright; - unsigned char rearleft; - unsigned char rearright; - unsigned char center; - unsigned char lfe; -} audio_volume; - -class Audio : public DrainTarget, public AbstractOption -{ - public: - Audio(); - virtual ~Audio(); - static Audio* getInstance(); - // static void setInstance(Audio* ); - - virtual int init(UCHAR streamType)=0; - virtual int shutdown()=0; - virtual int setStreamType(UCHAR streamType)=0; - virtual int setChannel()=0; - virtual int setSource()=0; - virtual int sync()=0; - virtual int play()=0; - virtual int stop()=0; - virtual int pause()=0; - virtual int unPause()=0; - virtual int reset()=0; - virtual int setVolume(int volume)=0; - virtual int mute()=0; - virtual int unMute()=0; - virtual bool supportsAc3()=0; - virtual bool maysupportAc3(){return false;} - virtual bool streamTypeSupported(int streamtype) - { - switch (streamtype) { - case 3: - case 4: - return true; - default: - return false; - }; - } - - int volumeUp(); - int volumeDown(); - int getVolume(); - int toggleUserMute(); - int systemMuteOn(); - int systemMuteOff(); - int doMuting(); - - // Audio stream type // FIXME these are MVP specific (probably!) - const static UCHAR MPEG2_PES = 2; - const static UCHAR MPEG1_PES = 3; // unused - const static UCHAR MP3 = 0; //media player - -#ifdef DEV - virtual int test()=0; -#endif - - protected: - static Audio* instance; - int initted; - UCHAR userMute; - UCHAR systemMute; - UCHAR muted; - int volume; - - audio_volume Aoffset; -}; - -#endif diff --git a/audioomx.cc b/audioomx.cc deleted file mode 100644 index 2ba6bb9..0000000 --- a/audioomx.cc +++ /dev/null @@ -1,2349 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon, 2009 Marten Richter - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#include -#include - -#include "videoomx.h" -#include "log.h" -#include "vdr.h" -#include "woptionpane.h" -#include "osdopenvg.h" -#include "util.h" - -extern "C" { -#include "libavutil/channel_layout.h" -#include "libavutil/opt.h" -} - -#include "audioomx.h" - -static const char* TAG = "AudioOMX"; - -AudioOMX::AudioOMX() -{ - initted = 0; - streamType = 0; - volume = 20; - muted = 0; - lastAType = MPTYPE_MPEG_AUDIO; - - canpass_ac3=false; - canpass_mp2=false; - canpass_mp3=false; - canpass_aac=false; - canpass_pcm_mch=false; - - prefered_ac3=0; //0 stereo PCM, 1 passthrough 2 Multichannel PCM - prefered_mp2=0; - prefered_mp3=0; - prefered_aac=0; - hdmi=true; - - omx_running=false; - - omx_aud_rend/*dec*/=0; - cur_input_buf_omx=NULL; - - ac3codec_libav=NULL; - ac3codec_context_libav=NULL; - - mp23codec_libav=NULL; - mp23codec_context_libav=NULL; - - resam_con_libav=NULL; - - - - decompress_buffer=NULL; - decompress_buffer_size=0; - decompress_buffer_filled=0; - mp3sameheader=0; - mp3sameheadercount=0; - - strcpy(L_VPE_OMX_AUDIO_REND, VPE_OMX_AUDIO_REND); -} - -AudioOMX::~AudioOMX() -{ -} - -int AudioOMX::init(UCHAR tstreamType) { - if (initted) - return 0; - initted = 1; - - streamType = tstreamType; - - if (!initAllParams()) { - shutdown(); - return 0; - } - - unMute(); - - decompress_buffer_size=20000; - decompress_buffer=static_cast(malloc(decompress_buffer_size)); - decompress_buffer_filled=0; - -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100) - av_register_all(); -#endif - - av_log_set_flags(AV_LOG_SKIP_REPEATED); - - ac3codec_libav = avcodec_find_decoder(AV_CODEC_ID_AC3); - if (ac3codec_libav == NULL) { - LogNT::getInstance()->debug(TAG, - "Find libav ac3 decoder failed"); - return 0; - } - - mp23codec_libav = avcodec_find_decoder(AV_CODEC_ID_MP3); - if (mp23codec_libav == NULL) { - LogNT::getInstance()->debug(TAG, - "Find libav mpeg audio decoder failed"); - return 0; - } - - aaclatmcodec_libav = avcodec_find_decoder(AV_CODEC_ID_AAC_LATM); - if (aaclatmcodec_libav == NULL) { - LogNT::getInstance()->debug(TAG, - "Find libav aac latm decoder failed"); - return 0; - } - - int ret; - - ret=vc_tv_hdmi_audio_supported( EDID_AudioFormat_eMPEG1,2,EDID_AudioSampleRate_e48KHz,0); - if (ret==0) { - //canpass_mp2=true; - // not implemented - LogNT::getInstance()->info(TAG, - "TV hdmi supports mpeg1 layer 1 and 2"); - } - ret=vc_tv_hdmi_audio_supported( EDID_AudioFormat_eMP3,2,EDID_AudioSampleRate_e48KHz,0); - if (ret==0) { - //canpass_mp3=true; - // not implemented - LogNT::getInstance()->info(TAG, - "TV hdmi supports mpeg1 layer 3"); - } - - ret=vc_tv_hdmi_audio_supported( EDID_AudioFormat_eAC3,6,EDID_AudioSampleRate_e48KHz,0); - if (ret==0) { - canpass_ac3=true; - LogNT::getInstance()->info(TAG, - "TV hdmi supports AC3"); - } - ret=vc_tv_hdmi_audio_supported( EDID_AudioFormat_eAAC,6,EDID_AudioSampleRate_e48KHz,0); - if (ret==0) { - canpass_aac=true; - //not implemented - LogNT::getInstance()->info(TAG, - "TV hdmi supports AAC"); - } - - canpass_pcm_mch=false; - - return 1; -} - -int AudioOMX::initAllParams() -{ - return (setStreamType(streamType) && setChannel() && setSource()); -} - -int AudioOMX::shutdown() -{ - if (!initted) return 0; - initted = 0; - - LogNT::getInstance()->debug(TAG, "audio shutdown called"); - DeAllocateCodecsOMX(); - - free(decompress_buffer); - decompress_buffer=NULL; - decompress_buffer_size=0; - decompress_buffer_filled=0; - - return 1; -} - -bool AudioOMX::loadOptionsFromServer(VDR* vdr) -{ - LogNT::getInstance()->debug(TAG, "AudioOMX config load"); - char *name=vdr->configLoad("AudioOMX","AC3DecodingMode"); - - if (name != NULL) { - if (STRCASECMP(name, "PCM") == 0) { - prefered_ac3 = 0; - } else if (STRCASECMP(name, "Passthrough") == 0) { - prefered_ac3 = 1; - } else if (STRCASECMP(name, "PCMMultichannel") == 0) { - prefered_ac3 = 2; - } - delete[] name; - } - - name = vdr->configLoad("AudioOMX", "Mp2DecodingMode"); - - if (name != NULL) { - if (STRCASECMP(name, "PCM") == 0) { - prefered_mp2 = 0; - } else if (STRCASECMP(name, "Passthrough") == 0) { - prefered_mp2 = 1; - } else if (STRCASECMP(name, "PCMMultichannel") == 0) { - prefered_mp2 = 2; - } - delete[] name; - } - - name = vdr->configLoad("AudioOMX", "AACDecodingMode"); - - if (name != NULL) { - if (STRCASECMP(name, "PCM") == 0) { - prefered_aac = 0; - } else if (STRCASECMP(name, "Passthrough") == 0) { - prefered_aac = 1; - } else if (STRCASECMP(name, "PCMMultichannel") == 0) { - prefered_aac = 2; - } - delete[] name; - } - - name = vdr->configLoad("AudioOMX", "Mp3DecodingMode"); - - if (name != NULL) { - if (STRCASECMP(name, "PCM") == 0) { - prefered_mp3 = 0; - } else if (STRCASECMP(name, "Passthrough") == 0) { - prefered_mp3 = 1; - } else if (STRCASECMP(name, "PCMMultichannel") == 0) { - prefered_mp3 = 2; - } - delete[] name; - } - - name = vdr->configLoad("AudioOMX", "AudioOutput"); - - if (name != NULL) { - if (STRCASECMP(name, "analog") == 0) { - hdmi = false; - } else if (STRCASECMP(name, "HDMI") == 0) { - hdmi = true; - } - delete[] name; - } - - - return true; - -} - -bool AudioOMX::handleOptionChanges(Option* option) -{ - if (Audio::handleOptionChanges(option)) - return true; - switch (option->id) { - case 4: { - if (STRCASECMP(option->options[option->userSetChoice], "analog") == 0) { - hdmi = false; - } else if (STRCASECMP(option->options[option->userSetChoice], "HDMI") - == 0) { - hdmi = true; - } - return true; - } - break; - case 1: { - if (STRCASECMP(option->options[option->userSetChoice], "PCM") == 0) { - prefered_ac3 = 0; - } else if (STRCASECMP(option->options[option->userSetChoice], - "Passthrough") == 0) { - prefered_ac3 = 1; - } else if (STRCASECMP(option->options[option->userSetChoice], - "PCMMultichannel") == 0) { - prefered_ac3 = 2; - } - } - break; - case 2: { - if (STRCASECMP(option->options[option->userSetChoice], "PCM") == 0) { - prefered_mp2 = 0; - } else if (STRCASECMP(option->options[option->userSetChoice], - "Passthrough") == 0) { - prefered_mp2 = 1; - } else if (STRCASECMP(option->options[option->userSetChoice], - "PCMMultichannel") == 0) { - prefered_mp2 = 2; - } - } - break; - case 3: { - if (STRCASECMP(option->options[option->userSetChoice], "PCM") == 0) { - prefered_mp3 = 0; - } else if (STRCASECMP(option->options[option->userSetChoice], - "Passthrough") == 0) { - prefered_mp3 = 1; - } else if (STRCASECMP(option->options[option->userSetChoice], - "PCMMultichannel") == 0) { - prefered_mp3 = 2; - } - } - break; - case 5: { - if (STRCASECMP(option->options[option->userSetChoice], "PCM") == 0) { - prefered_aac = 0; - } else if (STRCASECMP(option->options[option->userSetChoice], - "Passthrough") == 0) { - prefered_aac = 1; - } else if (STRCASECMP(option->options[option->userSetChoice], - "PCMMultichannel") == 0) { - prefered_aac = 2; - } - } - break; - }; - return false; - -} - -bool AudioOMX::saveOptionstoServer() -{ - - switch (prefered_ac3) { - case 0: - VDR::getInstance()->configSave("AudioOMX", "AC3DecodingMode", "PCM"); - break; - case 1: - VDR::getInstance()->configSave("AudioOMX", "AC3DecodingMode", - "Passthrough"); - break; - case 2: - VDR::getInstance()->configSave("AudioOMX", "AC3DecodingMode", - "PCMMultichannel"); - break; - }; - - switch (prefered_aac) { - case 0: - VDR::getInstance()->configSave("AudioOMX", "AACDecodingMode", "PCM"); - break; - case 1: - VDR::getInstance()->configSave("AudioOMX", "AACDecodingMode", - "Passthrough"); - break; - case 2: - VDR::getInstance()->configSave("AudioOMX", "AACDecodingMode", - "PCMMultichannel"); - break; - }; - - switch (prefered_mp2) { - case 0: - VDR::getInstance()->configSave("AudioOMX", "Mp2DecodingMode", "PCM"); - break; - case 1: - VDR::getInstance()->configSave("AudioOMX", "Mp2DecodingMode", - "Passthrough"); - break; - case 2: - VDR::getInstance()->configSave("AudioOMX", "Mp2DecodingMode", - "PCMMultichannel"); - break; - }; - - switch (prefered_mp3) { - case 0: - VDR::getInstance()->configSave("AudioOMX", "Mp3DecodingMode", "PCM"); - break; - case 1: - VDR::getInstance()->configSave("AudioOMX", "Mp3DecodingMode", - "Passthrough"); - break; - case 2: - VDR::getInstance()->configSave("AudioOMX", "Mp3DecodingMode", - "PCMMultichannel"); - break; - }; - - if (!hdmi) - VDR::getInstance()->configSave("AudioOMX", "AudioOutput", "analog"); - else - VDR::getInstance()->configSave("AudioOMX", "AudioOutput", "HDMI"); - - - return true; -} - -/*Option(UINT id, const char* displayText, const char* configSection, const char* configKey, UINT optionType, - UINT numChoices, UINT defaultChoice, UINT startInt, - const char * const * options, const char * const * optionkeys = NULL, AbstractOption* handler=NULL);*/ - -bool AudioOMX::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane) -{ - if (!Audio::addOptionsToPanes(panenumber,options,pane)) return false; - - - Option* option; - if (panenumber == 2) - { - - static const char* audioopts[]={"analog","HDMI"}; - option = new Option(4,tr("Audio Output"), "AudioOMX","AudioOutput",Option::TYPE_TEXT,2,0,0,audioopts,NULL,false,this); - options->push_back(option); - pane->addOptionLine(option); - - - char **ac3opts=new char *[3]; - int i=0; - ac3opts[i]=new char[strlen("PCM")+1]; - strcpy(ac3opts[i],"PCM"); - i++; - if (canpass_ac3) { - ac3opts[i]=new char[strlen("Passthrough")+1]; - strcpy(ac3opts[i],"PassThrough"); - i++; - } - if (canpass_pcm_mch) { - ac3opts[i]=new char[strlen("PCMMultichannel")+1]; - strcpy(ac3opts[i],"PCMMultichannel"); - i++; - } - option = new Option(1 ,tr("AC3 HDMI Mode"), "AudioOMX", "AC3DecodingMode", Option::TYPE_TEXT, i, 0, 0, ac3opts,NULL,true, this); - options->push_back(option); - pane->addOptionLine(option); - - /* char **aacopts = new char *[3]; - i = 0; - aacopts[i] = new char[strlen("PCM") + 1]; - strcpy(mp2opts[i], "PCM"); - i++; - if (canpass_aac) { - aacopts[i] = new char[strlen("Passthrough") + 1]; - strcpy(aacopts[i], "PassThrough"); - i++; - } - if (canpass_pcm_mch) { - aacopts[i] = new char[strlen("PCMMultichannel") + 1]; - strcpy(aacopts[i], "PCMMultichannel"); - i++; - } - option = new Option(5, tr("Mp2 HDMI Mode"), "AudioOMX", - "AACDecodingMode", Option::TYPE_TEXT, i, 0, 0, - aacopts, NULL, true, this); - options->push_back(option); - pane->addOptionLine(option); - - - char **mp2opts = new char *[3]; - i = 0; - mp2opts[i] = new char[strlen("PCM") + 1]; - strcpy(mp2opts[i], "PCM"); - i++; - if (canpass_mp2) { - mp2opts[i] = new char[strlen("Passthrough") + 1]; - strcpy(mp2opts[i], "PassThrough"); - i++; - } - if (canpass_pcm_mch) { - mp2opts[i] = new char[strlen("PCMMultichannel") + 1]; - strcpy(mp2opts[i], "PCMMultichannel"); - i++; - } - option = new Option(2, tr("Mp2 HDMI Mode"), "AudioOMX", - "Mp2DecodingMode", Option::TYPE_TEXT, i, 0, 0, - mp2opts, NULL, true, this); - options->push_back(option); - pane->addOptionLine(option); - - char **mp3opts = new char *[3]; - i = 0; - mp3opts[i] = new char[strlen("PCM") + 1]; - strcpy(mp3opts[i], "PCM"); - i++; - if (canpass_mp3) { - mp3opts[i] = new char[strlen("Passthrough") + 1]; - strcpy(mp3opts[i], "PassThrough"); - i++; - } - if (canpass_pcm_mch) { - mp3opts[i] = new char[strlen("PCMMultichannel") + 1]; - strcpy(mp3opts[i], "PCMMultichannel"); - i++; - } - option = new Option(3, tr("Mp3 HDMI Mode"), "AudioOMX", - "Mp2DecodingMode", Option::TYPE_TEXT, i, 0, 0, mp3opts, - NULL, true, this); - options->push_back(option); - pane->addOptionLine(option);*/ - // Comment unsupported modes out - - - } - - return true; -} - - -OMX_ERRORTYPE AudioOMX::EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE /* hcomp */, OMX_IN OMX_PTR /* appdata */, OMX_IN OMX_BUFFERHEADERTYPE* buffer) -{ - //LogNT::getInstance()->info(TAG, "EmptyBufferDone"); - AudioOMX* audio = static_cast(getInstance()); - audio->ReturnEmptyOMXBuffer(buffer); - return OMX_ErrorNone; -} - -void AudioOMX::ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* buffer) -{ - input_bufs_omx_mutex.lock(); - //LogNT::getInstance()->info(TAG, "ReturnEmptyOMXBuffer {}",input_bufs_omx_free.size()); - input_bufs_omx_free.push_back(buffer); - //LogNT::getInstance()->info(TAG, "ReturnEmptyOMXBuffer {}",input_bufs_omx_free.size()); - input_bufs_omx_mutex.unlock(); - VideoOMX* video = static_cast(Video::getInstance()); - video->signalOmx(); -} - -OMX_ERRORTYPE AudioOMX::FillBufferDone_OMX(OMX_IN OMX_HANDLETYPE /* hcomp */, OMX_IN OMX_PTR /* appdata */, OMX_IN OMX_BUFFERHEADERTYPE* /* buffer */) -{ - LogNT::getInstance()->info(TAG, "FillBufferDone"); - VideoOMX* video = static_cast(Video::getInstance()); - video->signalOmx(); - return OMX_ErrorNone; -} - -int AudioOMX::setStreamType(UCHAR /* type */) -{ - if (!initted) return 0; - - // if (ioctl(fdAudio, AV_SET_AUD_STREAMTYPE, type) != 0) return 0; - return 1; -} - -int AudioOMX::setChannel() -{ - if (!initted) return 0; - - // if (ioctl(fdAudio, AV_SET_AUD_CHANNEL, 0) != 0) return 0; - return 1; -} - -int AudioOMX::setSource() -{ - if (!initted) return 0; - - // if (ioctl(fdAudio, AV_SET_AUD_SRC, 1) != 0) return 0; - return 1; -} - -int AudioOMX::sync() -{ - if (!initted) return 0; - - // if (ioctl(fdAudio, AV_SET_AUD_SYNC, 2) != 0) return 0; - return 1; -} - -int AudioOMX::play() { - if (!initted) - return 0; - lastAType=MPTYPE_MPEG_AUDIO; - LogNT::getInstance()->debug(TAG, "enter play"); - - static_cast(Video::getInstance())->interlaceSwitch4Demux(); // switch resolution if necessary - - if (!AllocateCodecsOMX()) { - return 0; - } - return 1; -} - - -int AudioOMX::ChangeAudioDestination() //clock aka omx mutex needs to be locked -{ - OMX_ERRORTYPE error; - const char * destinations[]={"local","hdmi"}; - int dest=0; - if (hdmi) dest=1; - else dest=0; - - OMX_CONFIG_BRCMAUDIODESTINATIONTYPE auddest; - memset(&auddest,0,sizeof(auddest)); - auddest.nSize=sizeof(auddest); - auddest.nVersion.nVersion=OMX_VERSION; - strcpy((char *)auddest.sName, destinations[dest]); - - LogNT::getInstance()->debug(TAG, "setting destination to: {}",auddest.sName); - error=OMX_SetConfig(omx_aud_rend,OMX_IndexConfigBrcmAudioDestination,&auddest); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "Init OMX_IndexConfigBrcmAudioDestination failed {:#x} {:#x} {}", error,omx_aud_rend,auddest.sName); - DeAllocateCodecsOMX(); - return 0; - } - return 1; - - -} - -int AudioOMX::ChangeAudioPortConfig(bool disport) //clock aka omx mutex needs to be locked -{ - OMX_ERRORTYPE error; - //Ok first fidle a working configuration - LogNT::getInstance()->debug(TAG, - "ChangeAudioPortConfig"); - - OMX_AUDIO_CODINGTYPE encoding; - if (hdmi) { - switch (lastAType) { - case MPTYPE_MPEG_AUDIO: { - if (prefered_mp2 == 2 && false) { //not supported yet - - } else { - if (prefered_mp2 == 1 && canpass_mp2) { - passthrough = true; - encoding=OMX_AUDIO_CodingMP3; - } else { - passthrough = false; - encoding=OMX_AUDIO_CodingPCM; - } - } - } - break; - case MPTYPE_AAC_LATM: { - if (prefered_aac == 2 && false) { //not supported yet - - } else { - LogNT::getInstance()->debug(TAG, - "ChangeAudioPortConfig debug {} {}",prefered_aac,canpass_aac); - if (prefered_aac == 1 && canpass_aac) { - passthrough = true; - encoding=OMX_AUDIO_CodingAAC; - } else { - passthrough = false; - encoding=OMX_AUDIO_CodingPCM; - } - } - } - break; - case MPTYPE_AC3_PRE13: - case MPTYPE_AC3: { - if (prefered_ac3 == 2 && false) { //not supported yet - - } else { - LogNT::getInstance()->debug(TAG, - "ChangeAudioPortConfig debug {} {}",prefered_ac3,canpass_ac3); - if (prefered_ac3 == 1 && canpass_ac3) { - passthrough = true; - encoding=OMX_AUDIO_CodingDDP; - } else { - passthrough = false; - encoding=OMX_AUDIO_CodingPCM; - } - } - } - break; - case MPTYPE_MPEG_AUDIO_LAYER3: { - if (prefered_mp3 == 2 && false) { //not supported yet - - } else { - if (prefered_mp3 == 1 && canpass_mp2) { - passthrough = true; - encoding=OMX_AUDIO_CodingMP3; - } else { - passthrough = false; - encoding=OMX_AUDIO_CodingPCM; - } - } - } - break; - }; - } else { - passthrough=false; - encoding=OMX_AUDIO_CodingPCM; - //mch=false; // multichannel also false - } - - - - /*OMX_CONFIG_BOOLEANTYPE booly; - memset(&booly, 0, sizeof(booly)); - booly.nSize = sizeof(booly); - booly.nVersion.nVersion = OMX_VERSION; - if (passthrough) - booly.bEnabled = OMX_TRUE; - else - booly.bEnabled = OMX_FALSE; - - error = OMX_SetParameter(omx_aud_dec, OMX_IndexParamBrcmDecoderPassThrough, - &booly); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Init OMX_IndexParamBrcmDecoderPassThrough failed {:#x}", error); - DeAllocateCodecsOMX(); - return 0; - }*/ - VideoOMX* video = static_cast(Video::getInstance()); - if (disport) { - video->DisablePort(omx_aud_rend,omx_rend_input_port,false); - //DestroyInputBufsOMXwhilePlaying(); - //video->CommandFinished(omx_aud_rend,OMX_CommandPortDisable,omx_rend_input_port); - - } - - - OMX_AUDIO_PARAM_PORTFORMATTYPE format; - memset(&format, 0, sizeof(format)); - format.nSize = sizeof(format); - format.nVersion.nVersion = OMX_VERSION; - format.nPortIndex = omx_rend_input_port; - error = OMX_GetParameter(omx_aud_rend, OMX_IndexParamAudioPortFormat, - &format); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Get OMX_IndexParamAudioPortFormat failed {:#x} {}", error, - omx_rend_input_port); - return 0; - } - if (disport) - - LogNT::getInstance()->debug(TAG, - "Get OMX_IndexParamAudioPortFormat returned {}",format.eEncoding ); - format.eEncoding = encoding; - - error = OMX_SetParameter(omx_aud_rend, OMX_IndexParamAudioPortFormat, - &format); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Set OMX_IndexParamAudioPortFormat failed {:#x} {} {}", error, - omx_rend_input_port,format.eEncoding ); - //return 0; - } - - switch (encoding) { - case OMX_AUDIO_CodingPCM: { - OMX_AUDIO_PARAM_PCMMODETYPE audio_pcm; - memset(&audio_pcm, 0, sizeof(audio_pcm)); - audio_pcm.nSize = sizeof(audio_pcm); - audio_pcm.nVersion.nVersion = OMX_VERSION; - audio_pcm.nChannels = 2; - audio_pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF; - audio_pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF; - //audio_pcm.eChannelMapping[2]=OMX_AUDIO_ChannelMax; - audio_pcm.eNumData = OMX_NumericalDataSigned; - audio_pcm.eEndian = OMX_EndianLittle; - audio_pcm.bInterleaved = OMX_TRUE; - audio_pcm.nBitPerSample = 16; - audio_pcm.ePCMMode = OMX_AUDIO_PCMModeLinear; - audio_pcm.nChannels = 2; - audio_pcm.nSamplingRate = 48000; - audio_pcm.nPortIndex = omx_rend_input_port; - error = OMX_SetParameter(omx_aud_rend, OMX_IndexParamAudioPcm, - &audio_pcm); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Init OMX_IndexParamAudioPcm failed {:#x} {}", error, - omx_rend_input_port); - return 0; - } - } break; - case OMX_AUDIO_CodingDDP: { - OMX_AUDIO_PARAM_DDPTYPE audio_ddp; - memset(&audio_ddp, 0, sizeof(audio_ddp)); - audio_ddp.nSize = sizeof(audio_ddp); - audio_ddp.nVersion.nVersion = OMX_VERSION; - audio_ddp.nPortIndex = omx_rend_input_port; - audio_ddp.nChannels = 8; //unknown - audio_ddp.nBitRate=0; - audio_ddp.nSampleRate=48000; - audio_ddp.eChannelMapping[0] =OMX_AUDIO_ChannelLF; - audio_ddp.eChannelMapping[1] =OMX_AUDIO_ChannelRF; - audio_ddp.eChannelMapping[2] =OMX_AUDIO_ChannelCF; - audio_ddp.eChannelMapping[3] =OMX_AUDIO_ChannelLFE; - audio_ddp.eChannelMapping[4] =OMX_AUDIO_ChannelLR; - audio_ddp.eChannelMapping[5] =OMX_AUDIO_ChannelRR; - audio_ddp.eChannelMapping[6] =OMX_AUDIO_ChannelLS; - audio_ddp.eChannelMapping[7] =OMX_AUDIO_ChannelRS; - audio_ddp.eChannelMapping[8] =OMX_AUDIO_ChannelCS; - error = OMX_SetParameter(omx_aud_rend, OMX_IndexParamAudioDdp, - &audio_ddp); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Init OMX_IndexParamAudioDdp failed {:#x} {}", error, - omx_rend_input_port); - return 0; - } - - } break; - default: break; //Make compiler happy - }; - - - - if (disport) { - - //PrepareInputBufsOMX(false); - video->EnablePort(omx_aud_rend,omx_rend_input_port,false); - } - - - - return 1; - - - -} -int AudioOMX::InitDecoderLibAV() -{ - libav_mutex.lock(); - ac3codec_context_libav = avcodec_alloc_context3(ac3codec_libav); - if (!ac3codec_context_libav) { - LogNT::getInstance()->debug(TAG, "Alloc avcodec for ac3 decoding context failed!"); - return 0; - } - -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 34, 1) - ac3codec_context_libav->flags |= AV_CODEC_FLAG_TRUNCATED; -#else - ac3codec_context_libav->flags |= CODEC_FLAG_TRUNCATED; -#endif - -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 64, 101) - ac3codec_context_libav->request_channel_layout=2; -#else - ac3codec_context_libav->request_channels=2; -#endif - - int avc_ret = avcodec_open2(ac3codec_context_libav, ac3codec_libav, NULL); - if (avc_ret < 0) { - LogNT::getInstance()->debug(TAG, "Opening libav codec failed"); - libav_mutex.unlock(); - return 0; - } - - aaclatmcodec_context_libav = avcodec_alloc_context3(aaclatmcodec_libav); - if (!aaclatmcodec_context_libav) { - LogNT::getInstance()->debug(TAG, "Alloc avcodec for aac decoding context failed!"); - return 0; - } - -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 34, 1) - aaclatmcodec_context_libav->flags |= AV_CODEC_FLAG_TRUNCATED; -#else - aaclatmcodec_context_libav->flags |= CODEC_FLAG_TRUNCATED; -#endif - -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 64, 101) - aaclatmcodec_context_libav->request_channel_layout=2; -#else - aaclatmcodec_context_libav->request_channels=2; -#endif - - avc_ret = avcodec_open2(aaclatmcodec_context_libav, aaclatmcodec_libav, NULL); - if (avc_ret < 0) { - LogNT::getInstance()->debug(TAG, "Opening libav codec failed"); - libav_mutex.unlock(); - return 0; - } - - - mp23codec_context_libav = avcodec_alloc_context3(mp23codec_libav); - if (!ac3codec_context_libav) { - LogNT::getInstance()->debug(TAG, "Alloc avcodec for mp23 decoding context failed!"); - libav_mutex.unlock(); - return 0; - } - -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 34, 1) - mp23codec_context_libav->flags |= AV_CODEC_FLAG_TRUNCATED; -#else - mp23codec_context_libav->flags |= CODEC_FLAG_TRUNCATED; -#endif - -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 64, 101) - mp23codec_context_libav->request_channel_layout=2; -#else - mp23codec_context_libav->request_channels=2; -#endif - - avc_ret = avcodec_open2(mp23codec_context_libav, mp23codec_libav, NULL); - if (avc_ret < 0) { - LogNT::getInstance()->debug(TAG, "Opening libav codec failed"); - libav_mutex.unlock(); - return 0; - } - - resam_con_libav = swr_alloc(); - if (resam_con_libav == NULL) { - LogNT::getInstance()->debug(TAG, - "Alloc resample context failed"); - return 0; - } - - av_opt_set_int(resam_con_libav, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); // our standard format - av_opt_set_int(resam_con_libav, "out_sample_rate",48000,0); - av_opt_set_int(resam_con_libav, "out_sample_fmt",AV_SAMPLE_FMT_S16,0); - av_opt_set_int(resam_con_libav, "matrix_encoding",AV_MATRIX_ENCODING_DPLII,0); - - av_opt_set_int(resam_con_libav, "in_sample_rate",48000,0); - av_opt_set_int(resam_con_libav, "in_sample_fmt",AV_SAMPLE_FMT_S16,0); - av_opt_set_int(resam_con_libav, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); //just an example - - - av_init_packet(&incoming_paket_libav); -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 64, 101) - decode_frame_libav=av_frame_alloc(); -#else - decode_frame_libav=avcodec_alloc_frame(); -#endif - libav_mutex.unlock(); - decompress_buffer_filled=0; - - - - return 1; -} - -void AudioOMX::DeinitDecoderLibAV() { - - - libav_mutex.lock(); - if (ac3codec_context_libav) { - avcodec_close(ac3codec_context_libav); - av_free(ac3codec_context_libav); - ac3codec_context_libav = NULL; - - avcodec_close(aaclatmcodec_context_libav); - av_free(aaclatmcodec_context_libav); - aaclatmcodec_context_libav = NULL; - - av_free(decode_frame_libav); - - avcodec_close(mp23codec_context_libav); - av_free(mp23codec_context_libav); - mp23codec_context_libav = NULL; - - swr_free(&resam_con_libav); - resam_con_libav=NULL; - - - } - libav_mutex.unlock(); - -} - - -int AudioOMX::AllocateCodecsOMX() -{ - OMX_ERRORTYPE error; - static OMX_CALLBACKTYPE callbacks= {&VideoOMX::EventHandler_OMX,&EmptyBufferDone_OMX,&FillBufferDone_OMX}; - - LogNT::getInstance()->info(TAG, "Allocate Codecs OMX"); - //Clock, move later to audio - VideoOMX* video = static_cast(Video::getInstance()); - - if (!InitDecoderLibAV()) return 0;; - - - OMX_PORT_PARAM_TYPE p_param; - memset(&p_param,0,sizeof(p_param)); - p_param.nSize=sizeof(p_param); - p_param.nVersion.nVersion=OMX_VERSION; - - - if (!video->getClockAudioandInit(&omx_clock,&omx_clock_output_port)){ - return 0;// get the clock and init it if necessary - } - - /* TODO end */ - if (!video->idleClock()) { - return 0; - } - video->LockClock(); - - error = OMX_GetHandle(&omx_aud_rend, L_VPE_OMX_AUDIO_REND, NULL, &callbacks); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Init OMX audio rend failed {:#x}", error); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - if (!ChangeAudioDestination()) { - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - error = OMX_GetParameter(omx_aud_rend, OMX_IndexParamAudioInit, &p_param); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Init OMX audio rend OMX_GetParameter failed {:#x}", error); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - omx_rend_input_port = p_param.nStartPortNumber; - - - - - - error = OMX_GetParameter(omx_aud_rend, OMX_IndexParamOtherInit, &p_param); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Init OMX aud rend OMX_GetParameter failed {:#x}", error); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - // buggy return value - omx_rend_clock_port = p_param.nStartPortNumber; - - - - -/* error=OMX_GetHandle(&omx_aud_dec,VPE_OMX_AUDIO_DECODER,NULL,&callbacks); - - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "Init OMX audio decoder failed {:#x}", error); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - error=OMX_GetParameter(omx_aud_dec,OMX_IndexParamAudioInit,&p_param); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "Init OMX audio decoder OMX_GetParameter failed {:#x}", error); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - omx_codec_input_port=p_param.nStartPortNumber; - omx_codec_output_port=p_param.nStartPortNumber+1; - - if (!video->DisablePort(omx_aud_dec,omx_codec_input_port) || !video->DisablePort(omx_aud_dec,omx_codec_output_port)) { - LogNT::getInstance()->debug(TAG, "Disable Ports OMX audio decoder failed"); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - }*/ - - - - - if (!video->DisablePort(omx_aud_rend,omx_rend_input_port,true) ) { - LogNT::getInstance()->debug(TAG, "Disable Ports OMX audio rend failed {}",omx_rend_input_port); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - if ( !video->DisablePort(omx_aud_rend, omx_rend_clock_port, true)) { - LogNT::getInstance()->debug(TAG, - "Disable Ports OMX rend clock port failed {}",omx_rend_clock_port); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - - - - //Setuo chain - - - error=OMX_SetupTunnel(omx_clock,omx_clock_output_port,omx_aud_rend,omx_rend_clock_port); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "OMX_Setup tunnel clock to rend failed {:#x} {} {}", error,omx_clock_output_port,omx_rend_clock_port); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - if (!video->EnablePort(omx_clock,omx_clock_output_port,false) || !video->EnablePort(omx_aud_rend,omx_rend_clock_port,false) - ) { - LogNT::getInstance()->debug(TAG, "Enable Ports OMX clock rend failed"); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - if (!video->ChangeComponentState(omx_aud_rend,OMX_StateIdle)) { - LogNT::getInstance()->debug(TAG, "aud_rend idle ChangeComponentState"); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - - - - if ( !video->CommandFinished(omx_aud_rend,OMX_CommandPortEnable,omx_rend_clock_port)) { - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - if ( !video->CommandFinished(omx_clock,OMX_CommandPortEnable,omx_clock_output_port)) { - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - - - if (!ChangeAudioPortConfig(false)){ - LogNT::getInstance()->info(TAG, "Change AudioPortConfig failed"); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - -/* if (!video->ChangeComponentState(omx_aud_dec,OMX_StateIdle)) { - LogNT::getInstance()->debug(TAG, "aud_dec ChangeComponentState"); - DeAllocateCodecsOMX(); - return 0; - }*/ - - - - if (!PrepareInputBufsOMX(true)) { - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - - -/* error=OMX_SetupTunnel(omx_aud_dec,omx_codec_output_port,omx_aud_rend,omx_rend_input_port); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "OMX_Setup tunnel dec to render failed {:#x}", error); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - }*/ - - - -/* if (!video->EnablePort(omx_aud_dec,omx_codec_output_port,false) || !video->EnablePort(omx_aud_rend,omx_rend_input_port,false) - ) { - LogNT::getInstance()->debug(TAG, "Enable Ports OMX codec rend failed"); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - }*/ - -/* if ( !video->CommandFinished(omx_aud_dec,OMX_CommandPortEnable,omx_codec_output_port) - || !video->CommandFinished(omx_aud_rend,OMX_CommandPortEnable,omx_rend_input_port)) { - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - }*/ - - if (!video->ChangeComponentState(omx_aud_rend,OMX_StateExecuting)) { - LogNT::getInstance()->debug(TAG, "omx_aud_rend ChangeComponentState Execute"); - video->UnlockClock(); - DeAllocateCodecsOMX(); - return 0; - } - - - video->UnlockClock(); - omx_running=true; - setVolume(volume); - doMuting(); - video->clockUnpause(); - - - if (!video->setClockExecutingandRunning()) return 0; - - LogNT::getInstance()->info(TAG, "Allocate Codecs OMX finished"); - - return 1; -} - -int AudioOMX::PrepareInputBufsOMX(bool setportdef) //needs to be called with locvke omx clock mutex -{ - VideoOMX* video = static_cast(Video::getInstance()); - - OMX_ERRORTYPE error; - OMX_PARAM_PORTDEFINITIONTYPE port_def_type; - memset(&port_def_type,0,sizeof(port_def_type)); - port_def_type.nSize=sizeof(port_def_type); - port_def_type.nVersion.nVersion=OMX_VERSION; - port_def_type.nPortIndex=omx_rend_input_port;//omx_codec_input_port; - - error=OMX_GetParameter(omx_aud_rend/*dec*/,OMX_IndexParamPortDefinition, &port_def_type); - - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "Get OMX OMX_IndexParamPortDefinition failed {:#x}", error); - } - - - if (setportdef) { - port_def_type.nBufferCountActual=2; - port_def_type.nBufferSize=std::max(static_cast(port_def_type.nBufferSize),50000); // for transcoder important - - error=OMX_SetParameter(omx_aud_rend/*dec*/,OMX_IndexParamPortDefinition, &port_def_type); - - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "Set OMX OMX_IndexParamPortDefinition failed {:#x}", error); - } - } - - - error=OMX_SendCommand(omx_aud_rend/*dec*/,OMX_CommandPortEnable,omx_rend_input_port/*codec*/,0); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "Prepare Input bufs Send Command to enable port {:#x}", error); - return 0; - } - - input_bufs_omx_mutex.lock(); - for (unsigned int i=0; i< port_def_type.nBufferCountActual;i++) { - OMX_BUFFERHEADERTYPE *buf_head=NULL; - error=OMX_AllocateBuffer(omx_aud_rend/*dec*/,&buf_head,omx_rend_input_port/*codec*/,NULL,port_def_type.nBufferSize); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "Use OMX_AllocateBuffer failed {:#x}", error); - input_bufs_omx_mutex.unlock(); - return 0; - } - input_bufs_omx_all.push_back(buf_head); - input_bufs_omx_free.push_back(buf_head); - } - omx_first_frame=true; - - firstsynched=false; - cur_input_buf_omx=NULL; - input_bufs_omx_mutex.unlock(); - - if (!video->CommandFinished(omx_aud_rend/*dec*/,OMX_CommandPortEnable,omx_rend_input_port /*codec*/)) { - return 0; - } - - return 1; -} - -int AudioOMX::DestroyInputBufsOMX() //call with clock mutex locked -{ - OMX_ERRORTYPE error; - - cur_input_buf_omx=NULL; - input_bufs_omx_mutex.lock(); - for (UINT i=0; i< input_bufs_omx_all.size();i++) { - error=OMX_FreeBuffer(omx_aud_rend/*dec*/,omx_rend_input_port/*codec*/,input_bufs_omx_all[i]); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "Use OMX_FreeBuffer failed {:#x}", error); - input_bufs_omx_mutex.unlock(); - return 0; - } - - } - input_bufs_omx_all.clear(); - input_bufs_omx_free.clear(); - input_bufs_omx_mutex.unlock(); - - return 1; -} - -int AudioOMX::DestroyInputBufsOMXwhilePlaying() //call with clock mutex locked -{ - //OMX_ERRORTYPE error; - - cur_input_buf_omx=NULL; - input_bufs_omx_mutex.lock(); - while (input_bufs_omx_all.size()>0) { - if (input_bufs_omx_free.size()>0) { - // Destroy one buffer - std::vector::iterator itty=input_bufs_omx_all.begin(); - OMX_BUFFERHEADERTYPE* cur_buf=input_bufs_omx_free.front(); - for (; itty!= input_bufs_omx_all.end();itty++) { - if ((*itty)==cur_buf) { - input_bufs_omx_all.erase(itty); - input_bufs_omx_free.pop_front(); - break; - } - } - } else { - input_bufs_omx_mutex.unlock(); - MILLISLEEP(5); - input_bufs_omx_mutex.lock(); - } - } - - LogNT::getInstance()->debug(TAG, "DestroyInputBufsOMXwhilePlaying {} {}", input_bufs_omx_all.size(),input_bufs_omx_free.size()); - input_bufs_omx_mutex.unlock(); - return 1; -} - - -int AudioOMX::DeAllocateCodecsOMX() -{ - OMX_ERRORTYPE error; - omx_running=false; - VideoOMX* video = static_cast(Video::getInstance()); - LogNT::getInstance()->debug(TAG, "enter deallocatecodecsomx"); - - - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 1"); - if (cur_input_buf_omx) { - cur_input_buf_omx->nFlags|=OMX_BUFFERFLAG_EOS; - error=video->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/,cur_input_buf_omx); - if (error!=OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, "OMX_EmptyThisBuffer 6 failed {:#x}", error); - } - - cur_input_buf_omx=NULL;//write out old data - } - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 2"); - - video->LockClock(); - if (omx_aud_rend/*dec*/) { - // first stop the omx elements - /* if (!video->ChangeComponentState(omx_aud_dec,OMX_StateIdle)) { - LogNT::getInstance()->debug(TAG, "aud_dec ChangeComponentState"); - }*/ - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 3"); - - video->UnlockClock(); - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 4"); - video->idleClock(); - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 5"); - video->LockClock(); - - if (!video->ChangeComponentState(omx_aud_rend,OMX_StateIdle)) { - LogNT::getInstance()->debug(TAG, "aud_rend ChangeComponentState"); - } - - // TODO proper deinit sequence - // first flush all buffers - - error=OMX_SendCommand(omx_aud_rend,OMX_CommandFlush, omx_rend_input_port, NULL); - if (error!=OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, "OMX_Flush rend in failed {:#x}", error); - - } - - /* error=OMX_SendCommand(omx_aud_dec,OMX_CommandFlush, omx_codec_input_port, NULL); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "OMX_Flush codec out failed {:#x}", error); - - }*/ - - - /* if (!video->CommandFinished(omx_aud_dec,OMX_CommandFlush,omx_codec_input_port)) { - LogNT::getInstance()->debug(TAG, "flush cmd codec input failed"); - }*/ - - - - error=OMX_SendCommand(omx_clock,OMX_CommandFlush, omx_clock_output_port, NULL); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "OMX_Flush clock out failed {:#x}", error); - - } - - error=OMX_SendCommand(omx_aud_rend,OMX_CommandFlush, omx_rend_clock_port, NULL); - if (error!=OMX_ErrorNone){ - LogNT::getInstance()->debug(TAG, "OMX_Flush rend clock failed {:#x}", error); - - } - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 6"); - - if (!video->CommandFinished(omx_clock,OMX_CommandFlush,omx_clock_output_port) || - !video->CommandFinished(omx_aud_rend,OMX_CommandFlush,omx_rend_clock_port)) { - LogNT::getInstance()->debug(TAG, "flush cmd clock shed failed"); - } - - DestroyInputBufsOMX(); //We have to make sure that no buffers are in use - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 6a"); - DeinitDecoderLibAV(); - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 7"); - - //todo flushing - if (!video->DisablePort(omx_aud_rend,omx_rend_input_port,true)) { - LogNT::getInstance()->debug(TAG, "Disable Tunnel Port failed 1"); - } - - /* if (!video->DisablePort(omx_aud_dec,omx_codec_output_port,true)) { - LogNT::getInstance()->debug(TAG, "Disable Tunnel Port failed 6"); - } - - if (!video->DisablePort(omx_aud_dec,omx_codec_input_port,true)) { - LogNT::getInstance()->debug(TAG, "Disable Tunnel Port failed 7"); - }*/ - - - if (!video->DisablePort(omx_aud_rend,omx_rend_clock_port,true)) { - LogNT::getInstance()->debug(TAG, "Disable Tunnel Port failed 4"); - } - - if (!video->DisablePort(omx_clock,omx_clock_output_port,true)) { - LogNT::getInstance()->debug(TAG, "Disable Tunnel Port failed 5"); - } - - - - /* error=OMX_SetupTunnel(omx_aud_dec,omx_codec_output_port,NULL,NULL); - if (error!=OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, "OMX_Setup tunnel teardown failed {:#x}", error); - - }*/ - - - - error=OMX_SetupTunnel(omx_aud_rend,omx_rend_input_port,NULL,0); - if (error!=OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, "OMX_Setup tunnel teardown failed {:#x}", error); - - } - - error=OMX_SetupTunnel(omx_clock,omx_clock_output_port,NULL,0); - if (error!=OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, "OMX_Setup tunnel teardown failed {:#x}", error); - - } - - error=OMX_SetupTunnel(omx_aud_rend,omx_rend_clock_port,NULL,0); - if (error!=OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, "OMX_Setup tunnel teardown failed {:#x}", error); - - } - LogNT::getInstance()->debug(TAG, "deallocatecodecsomx mark 8"); - - - //error=OMX_FreeHandle(omx_aud_dec); - error=OMX_FreeHandle(omx_aud_rend); - video->UnlockClock(); - video->destroyClock(); - omx_aud_rend/*dec*/=NULL; - if (error!=OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, "FreeHandle failed {}", error); - } - } else { - - video->UnlockClock(); - DeinitDecoderLibAV(); - } - LogNT::getInstance()->debug(TAG, "leave deallocate codecs OMX"); - - return 1; -} - - - -int AudioOMX::stop() -{ - if (!initted) return 0; - - LogNT::getInstance()->debug(TAG, "Audio stop called"); - DeAllocateCodecsOMX(); - //if (ioctl(fdAudio, AV_SET_AUD_RESET, 0x11) != 0) return 0; - return 1; -} - -int AudioOMX::mute() { - if (!initted) - return 0; - LogNT::getInstance()->debug(TAG, "MUTE MUTE MUTE"); - VideoOMX* vw = static_cast(Video::getInstance()); - vw->LockClock(); - if (omx_running) { - - OMX_AUDIO_CONFIG_MUTETYPE amute; - memset(&amute, 0, sizeof(amute)); - amute.nSize = sizeof(amute); - amute.nVersion.nVersion = OMX_VERSION; - amute.nPortIndex = omx_rend_input_port; - amute.bMute = OMX_TRUE; - OMX_ERRORTYPE error= OMX_SetParameter(omx_aud_rend, OMX_IndexConfigAudioMute, - &amute); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Set OMX_IndexConfigAudioMute failed {:#x} {}", error, - omx_rend_input_port); - vw->UnlockClock(); - return 0; - } - - } - vw->UnlockClock(); - - muted = 1; - return 1; -} - -int AudioOMX::unMute() -{ - if (!initted) return 0; - - LogNT::getInstance()->debug(TAG, "MUTE OFF OFF OFF"); - VideoOMX* vw = static_cast(Video::getInstance()); - vw->LockClock(); - if (omx_running) { - - OMX_AUDIO_CONFIG_MUTETYPE amute; - memset(&amute, 0, sizeof(amute)); - amute.nSize = sizeof(amute); - amute.nVersion.nVersion = OMX_VERSION; - amute.nPortIndex = omx_rend_input_port; - amute.bMute = OMX_FALSE; - OMX_ERRORTYPE error = OMX_SetParameter(omx_aud_rend, OMX_IndexConfigAudioMute, - &amute); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Set OMX_IndexConfigAudioMute failed {:#x} {}", error, - omx_rend_input_port); - vw->UnlockClock(); - return 0; - } - } - - vw->UnlockClock(); - - muted = 0; - return 1; -} - -int AudioOMX::pause() -{ - if (!initted) return 0; - VideoOMX* vw = static_cast(Video::getInstance()); - vw->clockPause(); - return 1; -} - -int AudioOMX::unPause() -{ - if (!initted) return 0; - VideoOMX* vw = static_cast(Video::getInstance()); - vw->clockUnpause(); - return 1; -} - -int AudioOMX::reset() -{ - if (!initted) return 0; -//test(); - LogNT::getInstance()->debug(TAG, "reset called"); - DeAllocateCodecsOMX(); - -// if (ioctl(fdAudio, AV_SET_AUD_RESET, 0x11) != 0) return 0; -// LogNT::getInstance()->debug(TAG, "reset back"); - // if (ioctl(fdAudio, AV_SET_AUD_PLAY, 0) != 0) return 0; - - doMuting(); - return 1; -} - -int AudioOMX::setVolume(int tvolume) -{ - // parameter: 0 for silence, 20 for full - if ((tvolume < 0) || (tvolume > 20)) return 0; - -// volume = 2 * (20 - volume); -// Right, that one was rubbish... 0-10 were almost -// inaudible, 11-20 did what should have been done -// over the whole 0-20 range - volume=tvolume; - - VideoOMX* vw = static_cast(Video::getInstance()); - - vw->LockClock(); - if (omx_running) { - - OMX_AUDIO_CONFIG_VOLUMETYPE avol; - memset(&avol, 0, sizeof(avol)); - avol.nSize = sizeof(avol); - avol.nVersion.nVersion = OMX_VERSION; - avol.nPortIndex = omx_rend_input_port; - avol.bLinear=OMX_FALSE; - avol.sVolume.nValue =(volume-20)*200; - OMX_ERRORTYPE error = OMX_SetParameter(omx_aud_rend, OMX_IndexConfigAudioVolume, - &avol); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Set OMX_IndexConfigAudioVolume failed {:#x} {}", error, - omx_rend_input_port); - vw->UnlockClock(); - return 0; - } - - } - vw->UnlockClock(); - - return 1; -} - -#ifdef DEV -int AudioOMX::test() -{ -// ULLONG stc = 0; -// return ioctl(fdAudio, AV_SET_AUD_STC, &stc); - -/* aud_sync_parms_t a; - a.parm1 = 0; - a.parm2 = 0; -*/ -// int b = ioctl(fdAudio, AV_SET_AUD_DISABLE_SYNC, &a); - - - /*OK*/ //printf("Audio sync disable = %i\n", b); - - return 1; - - -} -#endif - -unsigned int AudioOMX::AdvanceMpAudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize) -{ - if (size<=2) return size; // silly; - unsigned int atest=0; - *framesize=0; - //inspired by libav parsing code - while (atest+1 reserved - //sanity check inspired by libav - - - const int sample_rates[4]={44100,48000,32000,0}; - const short bitrate_tab[2][3][15] = { { { 0, 32, 64, 96, 128, 160, - 192, 224, 256, 288, 320, 352, 384, 416, 448 }, { 0, 32, 48, - 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }, { - 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, - 256, 320 } }, { { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, - 160, 176, 192, 224, 256 }, { 0, 8, 16, 24, 32, 40, 48, 56, - 64, 80, 96, 112, 128, 144, 160 }, { 0, 8, 16, 24, 32, 40, - 48, 56, 64, 80, 96, 112, 128, 144, 160 } } }; - int lsf=0; - int mpeg2=0; - int layer=4-((data[atest+1]&0x06)>>1); - if (layer==4) {atest++;continue;} //sanity check - - int bitrate_index=(data[atest+2]&0xf0)>>4; - if (bitrate_index==0x0f || bitrate_index==0x0) {atest++;continue;} //sanity check - - int samplerate_index=(data[atest+2]&0x0C)>>2; - if (samplerate_index==0x03) {atest++;continue;} //sanity check - - int padding=(data[atest+2]&2)>>1; - if (0x10 & data[atest+1]) { - lsf=((data[atest+1]) &0x8)?0:1; - mpeg2=0; - } else { - lsf=1; - mpeg2=1; - } - int sample_rate=sample_rates[ samplerate_index]>>(lsf+mpeg2); - int frame_size=0; - int temp_frame_size=bitrate_tab[lsf][layer - 1][bitrate_index]; - if (layer==1) { - frame_size=(temp_frame_size*12000)/sample_rate; - frame_size=(frame_size+padding)*4; - } else if (layer==2) { - frame_size=(temp_frame_size*144000)/sample_rate; - frame_size=frame_size+padding; - } else { - frame_size=(temp_frame_size*144000)/(sample_rate<debug(TAG, "FRAME: {} {} {} {} {} {} {}",lsf,layer,bitrate_index,sample_rate,padding,temp_frame_size, frame_size); - //LogNT::getInstance()->debug(TAG, "FRAME DIAG: {:#x} {:#x} {:#x} {}",data[atest],data[atest+1],data[atest+2],mp3sameheadercount); - - if (mp3sameheadercount>4) { - *framesize=frame_size; - return atest; // probably FrameSync - } //skip it if the header changes too frequently - } - atest++; - } - return size; -} - -unsigned int AudioOMX::AdvanceAc3AudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize) -{ - if (size<=4) return size; // silly; - const int frm_size_tab[] = { 64, 64, 80, 80, 96, 96, 112, 112, 128, 128, - 160, 160, 192, 192, 224, 224, 256, 256, 320, 320, 384, 384, 448, - 448, 512, 512, 640, 640, 768, 768, 896, 896, 1024, 1024, 1152, - 1152, 1280, 1280, }; - unsigned int atest=0; - *framesize=20000; //if we do not find a start code do not decompress - while (atest+4>6; - unsigned char frmsize=(code &0x3f); - if (fscod!=0) LogNT::getInstance()->debug(TAG, "warning we only support 48 KHz sampling rate"); - *framesize=frm_size_tab[frmsize]*2; - return atest; // probably FrameSync - } - atest++; - } - return size; -} - -unsigned int AudioOMX::AdvanceAacLatmAudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize) -{ - if (size<=4) return size; // silly; - unsigned int atest=0; - *framesize=20000; //if we do not find a start code do not decompress - while (atest+4(Video::getInstance()); - video->LockClock(); - OMX_PARAM_U32TYPE audio_lat; - OMX_ERRORTYPE error; - memset(&audio_lat, 0, sizeof(audio_lat)); - audio_lat.nSize = sizeof(audio_lat); - audio_lat.nVersion.nVersion = OMX_VERSION; - audio_lat.nPortIndex = omx_rend_input_port; - - error = OMX_GetConfig(omx_aud_rend, OMX_IndexConfigAudioRenderingLatency, - &audio_lat); - video->UnlockClock(); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "Init OMX_IndexConfigAudioRenderingLatencyfailed {:#x} {}", error, - omx_rend_input_port); - return pts; // no correction in case of error - } - /*LogNT::getInstance()->debug(TAG, "Current audio latency {}", - audio_lat.nU32);*/ - - long long workpts=0; - workpts+=addsamples; - workpts-=audio_lat.nU32; - workpts*=10LL*1000LL*1000LL; - workpts=workpts/((long long)srate); //one second /samplerate - workpts+=pts; - - return workpts; -} - -bool AudioOMX::DrainTargetBufferFull() -{ - //Check, if we have OMX output buffers - bool full; - input_bufs_omx_mutex.lock(); - full=(input_bufs_omx_free.size()==0); - input_bufs_omx_mutex.unlock(); - return full; - -} - - -UINT AudioOMX::DeliverMediaPacket(MediaPacket mpacket, const UCHAR* buffer, - UINT *samplepos) { - /*First Check, if we have an audio sample*/ - VideoOMX* vw = static_cast(Video::getInstance()); - bool achange=false; - OMX_ERRORTYPE error; - //Log *logger=Log::getInstance(); - if (vw->InIframemode()) { - samplepos = 0; - MILLISLEEP(10); - return 0; //Not in iframe mode! - } - - if (!omx_running) return 0; // if we are not runnig do not do this - if (vw->isClockPaused()) return 0; //Block if we pause - //LogNT::getInstance()->debug(TAG, "DMP mark 1"); - - //LogNT::getInstance()->debug(TAG, "DeliverMediaPacketOMX time {}",mpacket.presentation_time); - -/* if (mpacket.synched && mpacket.presentation_time <= 0) { - *samplepos = mpacket.length; - firstsynched = false; - lsync=true; - LogNT::getInstance()->debug(TAG, - "DeliverMediaPacketOMX Frameskip"); - return mpacket.length; - }*/ - - //LogNT::getInstance()->debug(TAG, "DMP mark 2"); - - UINT headerstrip = 0; - if (mpacket.disconti) { - firstsynched = false; - decompress_buffer_filled=0; - if (cur_input_buf_omx) { - error = vw->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/, - cur_input_buf_omx); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "OMX_EmptyThisBuffer 1 failed {:#x}", error); - } - cur_input_buf_omx = NULL; - } - lsync=true; - } - //LogNT::getInstance()->debug(TAG, "DMP mark 3"); - if (mpacket.type != lastAType) {//Format Change //Push data out ! - firstsynched = false; - achange=true; - mp3sameheader=0; - LogNT::getInstance()->debug(TAG,"Notice audio type change {} {}", mpacket.type,lastAType); - lastAType = mpacket.type; - decompress_buffer_filled=0; - - if (cur_input_buf_omx) { - error = vw->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/, - cur_input_buf_omx); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "OMX_EmptyThisBuffer 2 failed {:#x}", error); - } - cur_input_buf_omx = NULL; - } - - int oldcancelstate; - int oldcanceltype; - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldcancelstate); - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldcanceltype); - vw->LockClock(); - if (!ChangeAudioPortConfig(true)) { - LogNT::getInstance()->debug(TAG, - "Changing audio port config failed", error); - } - vw->UnlockClock(); - pthread_setcancelstate(oldcancelstate, NULL); - pthread_setcanceltype(oldcanceltype, NULL); - lsync=true; - - } - //LogNT::getInstance()->debug(TAG, "DMP mark 4"); - - /*Inspect PES-Header */ - if (*samplepos == 0 && mpacket.type != MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader - headerstrip = buffer[mpacket.pos_buffer + 8] + 9; - if (mpacket.type == MPTYPE_AC3) - headerstrip += 4; //skip ac3 bytes - *samplepos += headerstrip; - if (mpacket.synched) { - if (cur_input_buf_omx) { - //cur_input_buf_omx->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; - error = vw->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/, - cur_input_buf_omx); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "OMX_EmptyThisBuffer 3 failed {:#x}", error); - } - //vw->AdjustAudioPTS(correctAudioLatency(lastreftimeOMX,cur_input_buf_omx->nFilledLen/(2*2),48000)); - - cur_input_buf_omx = NULL;//write out old data - } - firstsynched = true; - //decompress_buffer_filled=0; - } else { - if (!firstsynched) {// - *samplepos = mpacket.length;//if we have not processed at least one - decompress_buffer_filled=0; - //LogNT::getInstance()->debug(TAG, "DMP mark 5"); - return mpacket.length;//synched packet ignore it! - } - } - } - if (!cur_input_buf_omx) { - input_bufs_omx_mutex.lock(); - if (input_bufs_omx_free.size()==0) { - input_bufs_omx_mutex.unlock(); - //LogNT::getInstance()->debug(TAG, "DMP mark 6"); - //LogNT::getInstance()->debug(TAG, "Deliver MediaPacket no free sample"); - return 0; // we do not have a free media sample - - } - cur_input_buf_omx=input_bufs_omx_free.front(); - cur_input_buf_omx->nFilledLen=0; - cur_input_buf_omx->nOffset=0; - cur_input_buf_omx->nTimeStamp=VideoOMX::intToOMXTicks(0); - input_bufs_omx_free.pop_front(); - input_bufs_omx_mutex.unlock(); - } - //LogNT::getInstance()->debug(TAG, "DMP mark 7"); - - if (cur_input_buf_omx->nFilledLen == 0) {//will only be changed on first packet - if (mpacket.synched) { - //LogNT::getInstance()->debug(TAG, - // "packet synched marker"); - - //lastreftimePTS=mpacket.pts; - if (omx_first_frame) { // TODO time - cur_input_buf_omx->nFlags = OMX_BUFFERFLAG_STARTTIME; - LogNT::getInstance()->debug(TAG, "Starttime"); - omx_first_frame = false; - } else { - cur_input_buf_omx->nFlags = 0; - //cur_input_buf_omx->nFlags|=OMX_BUFFERFLAG_TIME_UNKNOWN; - } - lastreftimeOMX = mpacket.presentation_time; - //LogNT::getInstance()->debug(TAG, - // "Time code {} pts {} dts {}", lastreftimeOMX, mpacket.pts,mpacket.dts); - lastreftimePTS = mpacket.pts; - cur_input_buf_omx->nTimeStamp = VideoOMX::intToOMXTicks(lastreftimeOMX/10LL); // the clock component is faulty; - } else { - // LogNT::getInstance()->debug(TAG, - // "packet NOT synched marker"); - cur_input_buf_omx->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; - cur_input_buf_omx->nTimeStamp = VideoOMX::intToOMXTicks(0); - - } - if (mpacket.disconti || achange) { - cur_input_buf_omx->nFlags |= OMX_BUFFERFLAG_DISCONTINUITY; - //mp23codec_context_libav->frame_size=-1; - //ac3codec_context_libav->frame_size=-1; - } - - } - //LogNT::getInstance()->debug(TAG, "DMP mark 8"); - - if (*samplepos>mpacket.length) *samplepos=0; //propably the thread got interrupted and sample is not valid any more! - unsigned int haveToCopy=mpacket.length-*samplepos; - - if (passthrough) { - while (haveToCopy>0) { - //LogNT::getInstance()->debug(TAG, "DMP mark 9"); - if (lsync) { - unsigned int gotframesize=0; - int adv=0; - switch (mpacket.type) { - case MPTYPE_MPEG_AUDIO: - case MPTYPE_MPEG_AUDIO_LAYER3: { - adv = AdvanceMpAudioSync(buffer+mpacket.pos_buffer+*samplepos, - haveToCopy,&gotframesize); - } - break; - case MPTYPE_AC3: - case MPTYPE_AC3_PRE13: { - adv = AdvanceAc3AudioSync(buffer+mpacket.pos_buffer+*samplepos, - haveToCopy,&gotframesize); - } - break; - - case MPTYPE_AAC_LATM: { - adv = AdvanceAacLatmAudioSync(buffer+mpacket.pos_buffer+*samplepos, - haveToCopy,&gotframesize); - } - break; - }; - if (adv != (int)haveToCopy) { - lsync=false; - haveToCopy-=adv; - *samplepos+=adv; - } else { - *samplepos=mpacket.length; //no ac3 sync byte - //LogNT::getInstance()->debug(TAG, "DMP mark 10"); - return mpacket.length; - } - } - // so everything is fine now do a memcpy - int cancopy=min(haveToCopy,cur_input_buf_omx->nAllocLen-cur_input_buf_omx->nFilledLen); - memcpy(cur_input_buf_omx->pBuffer+cur_input_buf_omx->nFilledLen,buffer+mpacket.pos_buffer+*samplepos,cancopy); - haveToCopy-=cancopy; - cur_input_buf_omx->nFilledLen+=cancopy; - *samplepos+=cancopy; - //LogNT::getInstance()->debug(TAG, "DMP mark 11"); - - error = vw->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/, cur_input_buf_omx); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "OMX_EmptyThisBuffer 5 failed {:#x}", error); - } - cur_input_buf_omx=NULL; - if (haveToCopy>0) { - // get5 new buffer - input_bufs_omx_mutex.lock(); - if (input_bufs_omx_free.size()==0) { - input_bufs_omx_mutex.unlock(); - // LogNT::getInstance()->debug(TAG, "Deliver MediaPacket no free sample2"); - return *samplepos; // we do not have a free media sample - } - cur_input_buf_omx=input_bufs_omx_free.front(); - cur_input_buf_omx->nFilledLen=0; - cur_input_buf_omx->nOffset=0; - cur_input_buf_omx->nFlags=OMX_BUFFERFLAG_TIME_UNKNOWN; - cur_input_buf_omx->nTimeStamp=VideoOMX::intToOMXTicks(0); - input_bufs_omx_free.pop_front(); - input_bufs_omx_mutex.unlock(); - } - //LogNT::getInstance()->debug(TAG, "DMP mark 12"); - - } - //LogNT::getInstance()->debug(TAG, "DMP mark 13"); - - } else { - int len; - int gotta; - int framesize=0; - int errcount=0; - - AVCodecContext *current_context; - switch (mpacket.type) { - case MPTYPE_MPEG_AUDIO: - case MPTYPE_MPEG_AUDIO_LAYER3: { - current_context = mp23codec_context_libav; - if (current_context->frame_size<0) framesize=1152; //Maximum framesize - else framesize=current_context->frame_size; - }break; - case MPTYPE_AAC_LATM: { - current_context = aaclatmcodec_context_libav; - } break; - case MPTYPE_AC3: - case MPTYPE_AC3_PRE13: { - current_context = ac3codec_context_libav; - }break; - }; - - if (decompress_buffer_filled) { // have a remaining paket - incoming_paket_libav.data =(uint8_t*) decompress_buffer; - memcpy(decompress_buffer+decompress_buffer_filled, - buffer+mpacket.pos_buffer+*samplepos, - min(haveToCopy,decompress_buffer_size-decompress_buffer_filled)); - incoming_paket_libav.size = decompress_buffer_filled - +min(haveToCopy,decompress_buffer_size-decompress_buffer_filled); - //LogNT::getInstance()->debug(TAG,"Use saved audio buffer {} {} {}",mpacket.type,decompress_buffer_filled,mpacket.synched); - } else { - incoming_paket_libav.data =(uint8_t*) buffer+mpacket.pos_buffer+*samplepos; - incoming_paket_libav.size = haveToCopy; - } - //LogNT::getInstance()->debug(TAG, "DMP mark 18"); - - while (haveToCopy> 0 && errcount<3) { - - //LogNT::getInstance()->debug(TAG,"libav in {} {}",framesize,current_context->frame_size); - //LogNT::getInstance()->debug(TAG, "libav in {} {}", - // framesize, current_context->frame_size); - - bool donotdecompress=false; - unsigned int gotframesize=0; - // if (!decompress_buffer_filled) { // only do this if no old data is present - int adv = 0; - switch (mpacket.type) { - case MPTYPE_MPEG_AUDIO: - case MPTYPE_MPEG_AUDIO_LAYER3: { - adv = AdvanceMpAudioSync(incoming_paket_libav.data, - incoming_paket_libav.size,&gotframesize); - } - break; - case MPTYPE_AC3: - case MPTYPE_AC3_PRE13: { - adv = AdvanceAc3AudioSync(incoming_paket_libav.data, - incoming_paket_libav.size,&gotframesize); - } - break; - case MPTYPE_AAC_LATM: { - adv = AdvanceAacLatmAudioSync(incoming_paket_libav.data, - incoming_paket_libav.size,&gotframesize); - } - break; - }; - if (adv > 0 /*&& !decompress_buffer_filled*/) { - incoming_paket_libav.data += adv; - incoming_paket_libav.size-=adv; - haveToCopy -= adv; - *samplepos += adv; - /*if (current_context->frame_size>0) framesize=min(current_context->frame_size,haveToCopy); - else*/ framesize=haveToCopy; - //LogNT::getInstance()->debug(TAG,"Advance by {} {} from {}",adv,mpacket.type,*samplepos ); - if (haveToCopy <= 0) { - // LogNT::getInstance()->debug(TAG,"No sync code in packet remove {}",mpacket.type); - *samplepos=mpacket.length; - return mpacket.length; - } - - - // } // - - if (gotframesize>0 && gotframesize>haveToCopy) { - donotdecompress=true; - errcount=100; // exit loop - } - // else LogNT::getInstance()->debug(TAG,"Loop run"); - } - //LogNT::getInstance()->debug(TAG, "DMP mark 19"); - if (!donotdecompress) { - int oldcancelstate; - int oldcanceltype; - pthread_testcancel(); - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldcancelstate); - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldcanceltype); - libav_mutex.lock(); - if (!omx_running || !mp23codec_context_libav - || !ac3codec_context_libav) { - libav_mutex.unlock(); - return *samplepos; - } - libav_mutex.unlock(); - // LogNT::getInstance()->debug(TAG,"libav out"); - int save_size=incoming_paket_libav.size; - - if ((int)gotframesize <= incoming_paket_libav.size) { - if (gotframesize>0) incoming_paket_libav.size=gotframesize; - len = avcodec_decode_audio4(current_context, decode_frame_libav, - &gotta, &incoming_paket_libav); - } else { - //LogNT::getInstance()->debug(TAG, "FRAME:E {} {}",gotframesize,incoming_paket_libav.size); - gotta=0; - len=0; - } - //LogNT::getInstance()->debug(TAG, "FRAME:T {}",len); - incoming_paket_libav.size=save_size; - //LogNT::getInstance()->debug(TAG, "libav out1"); - pthread_setcancelstate(oldcancelstate, NULL); - pthread_setcanceltype(oldcanceltype, NULL); - pthread_testcancel(); - - } else { - gotta=0; - len=0; - } - //LogNT::getInstance()->debug(TAG, "libav out2"); - //LogNT::getInstance()->debug(TAG, "DMP mark 20"); - if (!omx_running) { - libav_mutex.unlock(); - return *samplepos; - } - - if (decompress_buffer_filled) { // reset to normal decoding - if (len>0) { - //LogNT::getInstance()->debug(TAG,"saved audio: {}",len); - haveToCopy -= min(len-decompress_buffer_filled,0); - *samplepos += min(len-decompress_buffer_filled,0); - //if (current_context->frame_size>0) framesize=min(current_context->frame_size,haveToCopy); - /*else*/ framesize=haveToCopy; - } else { - framesize=haveToCopy; - } - incoming_paket_libav.data =(uint8_t*) buffer+mpacket.pos_buffer+*samplepos; - errcount=0; - decompress_buffer_filled=0; - } else { - - if (len>0) { - incoming_paket_libav.data += len; - haveToCopy -= len; - *samplepos += len; - errcount=0; - /*if (current_context->frame_size>0) framesize=min(current_context->frame_size,haveToCopy); - else*/framesize=haveToCopy; - } else { - errcount++; - framesize=haveToCopy; - } - } - //LogNT::getInstance()->debug(TAG, "DMP mark 21"); - - incoming_paket_libav.size =framesize; - if (gotta) { - //LogNT::getInstance()->debug(TAG, - // "Got a frame"); - - int dsize = av_samples_get_buffer_size(NULL, - /*current_context->channels*/2, decode_frame_libav->nb_samples, - AV_SAMPLE_FMT_S16, 1); - /* int dsize_in = av_samples_get_buffer_size(NULL, - current_context->channels, decode_frame_libav->nb_samples, - current_context->sample_fmt, 1); -- unused */ - //if (current_context->channels==1) dsize*=2; // we convert mono to stereo - if ((cur_input_buf_omx->nFilledLen + dsize) - > cur_input_buf_omx->nAllocLen ) { - // I doubt that this will ever happen - // LogNT::getInstance()->debug(TAG, - // "P 2 Time code {} pts {}", lastreftimeOMX, mpacket.pts); - error = vw->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/, - cur_input_buf_omx); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "OMX_EmptyThisBuffer 4 failed {:#x}", error); - } - cur_input_buf_omx = NULL; - - if (!cur_input_buf_omx) { - int count = 0; - while (count < 10 && omx_running) { - count++; - input_bufs_omx_mutex.lock(); - if (input_bufs_omx_free.size() == 0) { - input_bufs_omx_mutex.unlock(); - // LogNT::getInstance()->debug(TAG, - // "Deliver MediaPacket no free sample"); - MILLISLEEP(5); - //LogNT::getInstance()->debug(TAG, "DMP mark22"); - if (!omx_running) return *samplepos; - //LogNT::getInstance()->debug(TAG, "DMP mark 23"); - continue; - } - cur_input_buf_omx = input_bufs_omx_free.front(); - cur_input_buf_omx->nFilledLen = 0; - cur_input_buf_omx->nOffset = 0; - cur_input_buf_omx->nTimeStamp = VideoOMX::intToOMXTicks(0); - cur_input_buf_omx->nFlags=OMX_BUFFERFLAG_TIME_UNKNOWN; - input_bufs_omx_free.pop_front(); - input_bufs_omx_mutex.unlock(); - break; - } - if (!cur_input_buf_omx) return *samplepos; - } - - } - - //LogNT::getInstance()->debug(TAG,"memcpy in {} {} {}" ,dsize,current_context->sample_rate,cur_input_buf_omx->nFilledLen); - - - av_opt_set_int(resam_con_libav, "in_sample_rate",decode_frame_libav->sample_rate,0); - av_opt_set_int(resam_con_libav, "in_sample_fmt",decode_frame_libav->format,0); - av_opt_set_int(resam_con_libav, "in_channel_layout",decode_frame_libav->channel_layout, 0); - //LogNT::getInstance()->error(TAG, "AV resampledata {} {} {} {}",current_context->channels,current_context->sample_rate,current_context->sample_fmt,current_context->channel_layout); - //LogNT::getInstance()->error(TAG, "AV resampledata2 {} {} {}",decode_frame_libav->sample_rate,decode_frame_libav->format,decode_frame_libav->channel_layout); - - int ret = swr_init(resam_con_libav); - if (ret<0) { - LogNT::getInstance()->error(TAG, "Opening AV resample failed {}",ret); - } else { - uint8_t *output=cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen; -/* - * old docs: - avresample_convert ( AVAudioResampleContext * avr, - uint8_t ** output, - int out_plane_size, - int out_samples, - uint8_t *const * input, - int in_plane_size, - int in_samples - ) - - old call: - avresample_convert(resam_con_libav, - &output, dsize, decode_frame_libav->nb_samples, - decode_frame_libav->extended_data, decode_frame_libav->linesize[0], decode_frame_libav->nb_samples); - - new docs: - swr_convert ( struct SwrContext * s, - uint8_t ** out, - int out_count, - const uint8_t ** in, - int in_count - ) - new call: - */ - //LogNT::getInstance()->debug(TAG, "Calling swr_convert"); - - swr_convert(resam_con_libav, &output, decode_frame_libav->nb_samples, (const uint8_t**)decode_frame_libav->extended_data, decode_frame_libav->nb_samples); - - swr_close(resam_con_libav); - } - - //LogNT::getInstance()->debug(TAG,"memcpy out"); - cur_input_buf_omx->nFilledLen += dsize; - } else { - //LogNT::getInstance()->debug(TAG,"Incomplete mpeg frames in pes packet {} {}",incoming_paket_libav.size,mpacket.length); - /* uint8_t a1=incoming_paket_libav.data[0]; - uint8_t a2=incoming_paket_libav.data[1]; - uint8_t a3=incoming_paket_libav.data[2]; - uint8_t a4=incoming_paket_libav.data[3];*/ - // LogNT::getInstance()->debug(TAG,"Header {:#x} {:#x} {:#x} {:#x}",a1,a2, - // a3,a4); - } - - } - //LogNT::getInstance()->debug(TAG, "DMP mark 24"); - decompress_buffer_filled=0; - if (haveToCopy ) { - //LogNT::getInstance()->debug(TAG,"We can not decompress {} save for later {} {:#x} {:#x}",haveToCopy,mpacket.type,incoming_paket_libav.data,mpacket.pos_buffer); - memcpy(decompress_buffer,incoming_paket_libav.data,min(haveToCopy,decompress_buffer_size)); - - decompress_buffer_filled=min(haveToCopy,decompress_buffer_size); - - } - - if (cur_input_buf_omx->nFilledLen) { - //LogNT::getInstance()->debug(TAG, - // "P 3 Time code {} pts {}", lastreftimeOMX, mpacket.pts); - error = vw->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/, cur_input_buf_omx); - if (error != OMX_ErrorNone) { - LogNT::getInstance()->debug(TAG, - "OMX_EmptyThisBuffer 5 failed {:#x}", error); - } - //if (mpacket.synched) vw->AdjustAudioPTS(correctAudioLatency(lastreftimeOMX,cur_input_buf_omx->nFilledLen/(2*2),48000)); - cur_input_buf_omx = NULL; - } - } - - - //LogNT::getInstance()->debug(TAG, "DMP mark 25"); - - *samplepos=mpacket.length; - return mpacket.length; - -} - -long long AudioOMX::SetStartOffset(long long curreftime, bool *rsync) -{ - VideoOMX* vw = dynamic_cast(Video::getInstance()); - return vw->SetStartAudioOffset(curreftime,rsync); -} - -void AudioOMX::ResetTimeOffsets() -{ - VideoOMX* vw = dynamic_cast(Video::getInstance()); - vw->ResetTimeOffsets(); -} diff --git a/audioomx.h b/audioomx.h deleted file mode 100644 index 556f0f1..0000000 --- a/audioomx.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon, 2009,2012 Marten Richter - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef AUDIOOMX_H -#define AUDIOOMX_H - -#include -#include -#include -#include -#include - -extern "C" { -#include -#include -#include -} - -#include "defines.h" -#include "audio.h" -#include "videoomx.h" - -class AudioOMX : public Audio -{ - friend class VideoOMX; - public: - AudioOMX(); - virtual ~AudioOMX(); - - int init(UCHAR streamType); - int shutdown(); - - int setStreamType(UCHAR streamType); - int setChannel(); - int setSource(); - int sync(); - int play(); - int stop(); - int pause(); - int unPause(); - int reset(); - int setVolume(int volume); - int mute(); - int unMute(); - bool supportsAc3() { return true; } - bool maysupportAc3(){return true;} - bool streamTypeSupported(int streamtype) - { - switch (streamtype) { - case 0x11: //AAC LATM packaging - case 0x6A://ac3 - case 3: //mpeg 1 layer 1 and 2 - case 4: - return true; - default: - return false; - }; - } - - - //Writing Data to Audiodevice - virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); - virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos); - UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer,UINT *samplepos); - - virtual long long SetStartOffset(long long curreftime, bool *rsync); - virtual void ResetTimeOffsets(); - - virtual bool DrainTargetReady() {return omx_running;}; - virtual bool DrainTargetBufferFull(); - - - UCHAR getLastAType() {return lastAType;} - - bool loadOptionsFromServer(VDR* vdr); - bool saveOptionstoServer(); - bool addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane); - bool handleOptionChanges(Option* option); - - -#ifdef DEV - int test(); -#endif - - private: - int initAllParams(); - UCHAR streamType; - UCHAR lastAType; - bool firstsynched; - - MediaPacket packet; - UINT packetpos; - - - bool hdmi; // use hdmi as audio output - bool passthrough; // use audio passthrough for the current audio type - - bool canpass_aac; - bool canpass_ac3; - bool canpass_mp2; - bool canpass_mp3; - bool canpass_pcm_mch; - - - int prefered_aac; - int prefered_ac3; //0 stereo PCM, 1 passthrough 2 Multichannel PCM - int prefered_mp2; - int prefered_mp3; - - - - static OMX_ERRORTYPE EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp,OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver); - static OMX_ERRORTYPE FillBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver); - - - - unsigned int AdvanceAc3AudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize); - unsigned int AdvanceAacLatmAudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize); - unsigned int AdvanceMpAudioSync(const UCHAR *data,unsigned int size,unsigned int *framesize); - - - void ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* bulibaver); - - // OMX_HANDLETYPE omx_aud_dec; - OMX_HANDLETYPE omx_aud_rend; - OMX_HANDLETYPE omx_clock; - - //OMX_U32 omx_codec_input_port; - //OMX_U32 omx_codec_output_port; - OMX_U32 omx_rend_input_port; - OMX_U32 omx_rend_clock_port; - OMX_U32 omx_clock_output_port; - - long long lastreftimeOMX; - ULLONG lastreftimePTS; - - - - int AllocateCodecsOMX(); - int DeAllocateCodecsOMX(); - - int PrepareInputBufsOMX(bool setportdef); - int DestroyInputBufsOMX(); - int DestroyInputBufsOMXwhilePlaying(); - - int ChangeAudioPortConfig(bool disport); - int ChangeAudioDestination(); - long long correctAudioLatency(long long pts,int addsamples,int srate); - - std::vector input_bufs_omx_all; - std::list input_bufs_omx_free; - std::mutex input_bufs_omx_mutex; - OMX_BUFFERHEADERTYPE* cur_input_buf_omx; - - bool omx_running; - bool omx_first_frame; - std::mutex libav_mutex; - - AVCodec *aaclatmcodec_libav; - AVCodecContext *aaclatmcodec_context_libav; - AVCodec *ac3codec_libav; - AVCodecContext *ac3codec_context_libav; - AVCodec *mp23codec_libav; - AVCodecContext *mp23codec_context_libav; - AVPacket incoming_paket_libav; - AVFrame *decode_frame_libav; - SwrContext* resam_con_libav; - - - UCHAR * decompress_buffer; - unsigned int decompress_buffer_size; - unsigned int decompress_buffer_filled; - bool lsync; - - unsigned int mp3sameheader; - int mp3sameheadercount; - - - int InitDecoderLibAV(); - void DeinitDecoderLibAV(); - - char L_VPE_OMX_AUDIO_REND[128]; - -}; - -#endif diff --git a/audioplayer.cc b/audioplayer.cc deleted file mode 100644 index 44ade44..0000000 --- a/audioplayer.cc +++ /dev/null @@ -1,783 +0,0 @@ -/* - Copyright 2004-2006 Chris Tallon, Andreas Vogel - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#include "demuxeraudio.h" -#include "video.h" -#include "messagequeue.h" -#include "i18n.h" -#include "boxx.h" -#include "oldlog.h" -#include "media.h" -#include "mediaplayer.h" - -#include "audioplayer.h" - -//how often do we retry if there is no data in stream -#define MAXTRY 50 - -AudioPlayer * AudioPlayer::instance=NULL; - -AudioPlayer * AudioPlayer::getInstance(Boxx * parent,bool create) { -// Log::getInstance()->log("AudioPlayer",Log::DEBUG,"getInstance for view %p, instance=%p",parent,instance); - AudioPlayer *np=instance; - if (! np && ! create) return NULL; - if (! np) { - np=new AudioPlayer(parent); - np->run(); - instance=np; - } - instance->threadLock(); - instance->frontend=parent; - instance->threadUnlock(); - return instance; -} - -AudioPlayer::AudioPlayer(Boxx *parent) : afeed(this) -{ - frontend=parent; - audio = Audio::getInstance(); - logger = Log::getInstance(); - vdr = VDR::getInstance(); - logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorI"); - running=true; - playerRunnig=false; - streampos = 0; - bytesWritten=0; - state = S_STOP; - requestState=S_STOP; - feederState=FEEDER_STOP; - - threadBuffer = NULL; - - Video::getInstance()->turnVideoOff(); - requestedSequence=0; - sequence=0; - playSequence=0; - currentPlaySequence=-1; - uri=NULL; - demuxer=new DemuxerAudio(); - logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorII"); - if (!demuxer->init(this, audio, NULL, NULL, 0, DemuxerAudio::PACKET_SIZE+200,0)) - { - logger->log("AudioPlayer", Log::ERR, "Demuxer failed to init"); - shutdown(); - return ; - } - logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorIII"); - afeed.init(); - audio->reset(); - lenInBytes=0; - logger->log("AudioPlayer", Log::DEBUG, "Audio player created"); - canPosition=false; -} - -AudioPlayer::~AudioPlayer() -{ - if (threadBuffer) free(threadBuffer); - Timers::getInstance()->cancelTimer(this,1); - controlFeeder(FEEDER_STOP); - audio->reset(); - audio->setStreamType(Audio::MPEG2_PES); - delete demuxer; - demuxer=NULL; - delete uri; -} - -void AudioPlayer::controlFeeder(int feederAction) { - logger->log("AudioPlayer",Log::DEBUG,"control feeder old=%d, new=%d",feederState,feederAction); - switch (feederAction) { - case FEEDER_START: - case FEEDER_UNPAUSE: - if (feederState == FEEDER_STOP) - afeed.start(); - afeed.enable(); - break; - case FEEDER_STOP: - if (feederState != FEEDER_STOP) - afeed.stop(); - break; - case FEEDER_PAUSE: - afeed.disable(); - break; - } - feederState=feederAction; -} - - -void AudioPlayer::run() { - if (playerRunnig) return; - playerRunnig=true; - threadStart(); -} - - -void AudioPlayer::shutdown() -{ - running=false; - if (playerRunnig) { - threadSignalNoLock(); - //wait for the player thread to stop - logger->log("AudioPlayer",Log::DEBUG,"shutdown - warting for player thread to stop"); - //at most wait 10s - for (int loopcount=200;playerRunnig && loopcount > 0;loopcount--) { - MILLISLEEP(50); - } - if (playerRunnig) { - logger->log("AudioPlayer",Log::ERR,"shutdown - unable to stop player within 10s"); - } - } - instance=NULL; - delete this; -} - -bool AudioPlayer::isPlayerRunning() { - return playerRunnig; -} - -int AudioPlayer::setRequestedState(UCHAR rstate) { - int rt=0; - threadLock(); - requestState=rstate; - requestedSequence++; - rt=requestedSequence; - threadUnlock(); - return rt; -} - - -UCHAR AudioPlayer::getState() { - UCHAR rt=0; - threadLock(); - rt=state; - threadUnlock(); - return rt; -} - -void AudioPlayer::setState(UCHAR s) { - threadLock(); - state=s; - threadUnlock(); -} - -//------------------- externally called functions -------------------------- -int AudioPlayer::play(const MediaURI * u) -{ - logger->log("AudioPlayer", Log::DEBUG, "play request for %s", u->getName()); - int rt=0; - threadLock(); - if (uri) delete uri; - uri=new MediaURI(u); - requestState=S_PLAY; - requestedSequence++; - rt=requestedSequence; - playSequence++; - threadUnlock(); - threadSignalNoLock(); - return rt; -} - -int AudioPlayer::stop() -{ - int rt= setRequestedState(S_STOP); - threadSignalNoLock(); - return rt; -} - -int AudioPlayer::pause() -{ - int rt= setRequestedState(S_PAUSE); - threadSignalNoLock(); - return rt; -} -int AudioPlayer::unpause() -{ - int rt= setRequestedState(S_PLAY); - threadSignalNoLock(); - return rt; -} - -int AudioPlayer::fastForward(){ - if (! canPosition) return 1; - int rt=setRequestedState(S_FF); - threadSignalNoLock(); - return rt; -} - -int AudioPlayer::fastBackward(){ - if (! canPosition) return 1; - int rt=setRequestedState(S_BACK); - threadSignalNoLock(); - return rt; -} -int AudioPlayer::jumpToPercent(double percent){ - if (! canPosition) return 1; - threadLock(); - ULONG fsec=demuxer->getSecondsFromLen(lenInBytes); - ULONG npos=streampos; - if (fsec != 0) { - fsec=(ULONG)(((double)fsec*percent)/(double)100); - npos=demuxer->positionFromSeconds(fsec); - logger->log("AudioPlayer",Log::DEBUG,"new pos %ld from demux",npos); - } - if (npos == 0) { - //the demuxer cannot help us - npos=(ULONG)(((double)lenInBytes*percent)/(double)100); - logger->log("AudioPlayer",Log::DEBUG,"new pos %ld without demux",npos); - } - if (npos > lenInBytes) npos=lenInBytes-1; - requestedStreampos=npos; - requestState=S_POSITION; - requestedSequence++; - threadUnlock(); - //no need to wait here... - return 0; -} - -int AudioPlayer::skipForward(int seconds) { - if (! canPosition) return 1; - threadLock(); - ULONG curr=demuxer->getSecondsFromLen(streampos); - ULONG dest=demuxer->positionFromSeconds(curr+(UINT)seconds); - if (dest != 0) { - logger->log("AudioPlayer",Log::DEBUG,"new pos %ld skip %ds",dest,seconds); - requestedStreampos=dest; - } - requestState=S_POSITION; - requestedSequence++; - threadUnlock(); - return 0; -} -int AudioPlayer::skipBackward(int seconds) { - if (! canPosition) return 1; - threadLock(); - ULONG curr=demuxer->getSecondsFromLen(streampos); - if (curr > (UINT)seconds) { - ULONG dest=demuxer->positionFromSeconds(curr-(UINT)seconds); - if (dest != 0) { - logger->log("AudioPlayer",Log::DEBUG,"new pos %ld skip %ds",dest,seconds); - requestedStreampos=dest; - requestState=S_POSITION; - requestedSequence++; - } - } - threadUnlock(); - return 0; -} - - - -// ----------------------------------- Internal functions - - -void AudioPlayer::sendFrontendMessage(ULONG para) -{ - logger->log("AudioPlayer", Log::DEBUG, "sending frontend message %ld",para); - Message* m = new Message(); - threadLock(); - m->to = frontend; - threadUnlock(); - m->from = this; - m->message = Message::PLAYER_EVENT; - m->parameter = para; - MessageQueue::getInstance()->postMessage(m); -} - -//open a new file -//called within the thread! -int AudioPlayer::openFile() { - threadLock(); - MediaURI fn(uri); - threadUnlock(); - demuxer->reset(); - streampos=0; - bytesWritten=0; - MediaPlayer::getInstance()->closeMediaChannel(2); - int rt=MediaPlayer::getInstance()->openMedium(2,&fn,&lenInBytes,0,0); - Log::getInstance()->log("Audioplayer", Log::DEBUG, "request file rt=%d file=%s",rt,fn.getDisplayName()); - if (rt != 0) { - return 1; - } - MediaInfo mi; - rt=MediaPlayer::getInstance()->getMediaInfo(2,&mi); - canPosition=mi.canPosition; - ULONG rsize=0; - UCHAR *idbuf=NULL; - if (canPosition) { - rt=MediaPlayer::getInstance()->getMediaBlock(2,0,demuxer->headerBytes(),&rsize,&idbuf); - } - else { - rt=-1; - } - if (rsize < demuxer->headerBytes() || rt != 0 ) { - if (idbuf) free(idbuf); - Log::getInstance()->log("Audioplayer", Log::DEBUG, "unable to get header for file %s",fn.getName()); - return 0; - } - threadLock(); - int hdrpos=demuxer->checkStart(idbuf,rsize); - threadUnlock(); - if (hdrpos >= 0) { - streampos=hdrpos; - } - if (idbuf) free(idbuf); - idbuf=NULL; - if (demuxer->getId3Tag() == NULL && canPosition) { - //OK - look at the end - rt=MediaPlayer::getInstance()->getMediaBlock(2,lenInBytes-demuxer->footerBytes(),demuxer->footerBytes(),&rsize,&idbuf); - if (rsize < demuxer->footerBytes() || rt != 0) { - if (idbuf) free(idbuf); - Log::getInstance()->log("Audioplayer", Log::DEBUG, "unable to get footer for file %s",fn.getName()); - return 0; - } - threadLock(); - hdrpos=demuxer->checkID3(idbuf,rsize); - threadUnlock(); - if (hdrpos < 0) { - Log::getInstance()->log("Audioplayer", Log::DEBUG, "no ID3 in footer for file %s",fn.getName()); - } - free(idbuf); - } - return 0; -} -//method called by the playing thread to handle -//"commands" by the frontend -UCHAR AudioPlayer::checkState() -{ - threadLock(); - UCHAR rstate=requestState; - UCHAR cstate=state; - int rseq=requestedSequence; - int cseq=sequence; - int fseq=playSequence; - threadUnlock(); - //flag to decide which message to send - //to frontend - bool newFile=false; - - if ( rseq > cseq) { - logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u", cstate, rstate); - switch(rstate) - { - case S_PAUSE: - if (cstate != S_PLAY && cstate != S_FF && cstate != S_PAUSE) { - rstate=cstate; //ignore request - break; - } - else { - if (cstate != S_PAUSE) { - skipfactor=0; - demuxer->setSkipFactor(0); - audio->mute(); - audio->pause(); - break; - } - } - //if cstate==S_PAUSE fallthrough to S_PLAY - rstate=S_PLAY; - case S_PLAY: // to S_PLAY - skipfactor=0; - demuxer->setSkipFactor(0); - if (fseq != currentPlaySequence || cstate == S_STOP || cstate == S_ERROR || cstate == S_DONE) { - //this is a new play request interrupting the current - logger->log("AudioPlayer", Log::DEBUG, "replay from start fseq=%d, startseq=%d", fseq, currentPlaySequence); - threadLock(); - playSequence=fseq; - threadUnlock(); - currentPlaySequence=fseq; - newFile=true; - if (cstate != S_DONE) audio->mute(); - int rt=openFile(); - if (rt != 0) { - rstate=S_ERROR; - } - else { - audio->unPause(); - if (cstate != S_DONE) { - //flush only if we are not coming from stream end - thisRead=0; - thisWrite=0; - if (threadBuffer) free(threadBuffer); - threadBuffer=NULL; - controlFeeder(FEEDER_STOP); - demuxer->flush(); - controlFeeder(FEEDER_START); - audio->reset(); - audio->systemMuteOff(); - audio->setStreamType(Audio::MP3); - } - audio->unMute(); - audio->play(); - } - } - else if (cstate == S_PAUSE){ - newFile=true; - audio->unPause(); - audio->unMute(); - } - else if (cstate == S_FF || S_BACK) { - ; - } - else { - rstate=cstate; - } - break; - case S_DONE: - Timers::getInstance()->setTimerD(this,1,4); - //inform the frontend - break; - case S_FF: - if (cstate != S_PLAY && cstate != S_PAUSE && cstate != S_FF) { - rstate=cstate; - } - else { - if (skipfactor == 0) skipfactor=2; - else skipfactor=skipfactor<<1; - if (skipfactor > 16 ) skipfactor=2; - demuxer->setSkipFactor(skipfactor); - } - if (cstate == S_PAUSE) { - audio->unPause(); - audio->unMute(); - } - break; - case S_POSITION: - if (cstate != S_PLAY && cstate != S_PAUSE) { - rstate=cstate; - } - else { - audio->mute(); - audio->unPause(); - controlFeeder(FEEDER_STOP); - demuxer->flush(); - thisRead=0; - thisWrite=0; - if (threadBuffer) free(threadBuffer); - threadBuffer=NULL; - streampos=requestedStreampos; - bytesWritten=streampos; - audio->reset(); - audio->setStreamType(Audio::MP3); - controlFeeder(FEEDER_START); - audio->unMute(); - audio->play(); - rstate=S_PLAY; - } - break; - default: // to S_STOP - rstate=S_STOP; - audio->mute(); - audio->stop(); - audio->unPause(); - controlFeeder(FEEDER_STOP); - demuxer->flush(); - thisRead=0; - thisWrite=0; - if (threadBuffer) free(threadBuffer); - threadBuffer=NULL; - logger->log("AudioPlayer", Log::DEBUG, "stop handled fseq: %d startseq %d completed", playSequence, currentPlaySequence); - break; - } - threadLock(); - state=rstate; - sequence=rseq; - threadUnlock(); - if (newFile) sendFrontendMessage(NEW_SONG); - else if (cstate != rstate && rstate != S_DONE ) { - sendFrontendMessage(STATUS_CHANGE); - //any change after done cancels the "done" timer - Timers::getInstance()->cancelTimer(this,1); - } - logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u completed seq=%d, nf=%s", cstate, rstate,rseq,newFile?"true":"false"); - //we return the newly set state - return rstate; - } - //rstate could be different but no new request - so return cstate - return cstate; -} - - - - -// ----------------------------------- Feed thread - -void AudioPlayer::waitTimed(int ms) { - threadLock(); - struct timespec nt; - int sec=ms/1000; - int us=1000*(ms - 1000*sec); -#ifndef WIN32 - struct timeval ct; - gettimeofday(&ct,NULL); - nt.tv_sec=ct.tv_sec+sec; - nt.tv_nsec=1000*us+1000*ct.tv_usec; -#else - DWORD ct=timeGetTime(); - nt.tv_sec=ct/1000+sec; - nt.tv_nsec=1000*us+1000*ct*1000; -#endif - threadWaitForSignalTimed(&nt); - threadUnlock(); -} - -void AudioPlayer::threadMethod() -{ - logger->log("AudioPlayer", Log::DEBUG, "player thread started"); - thisWrite=0; - thisRead=0; - int retrycount=0; - while(1) - { - UCHAR cstate=checkState(); - if (! running) { - break; - } - if (cstate != S_PLAY && cstate != S_FF && cstate != S_BACK) { - waitTimed(500); - continue; - } - threadCheckExit(); - - if (thisWrite == thisRead) { - //TODO: use normal blocks... - thisRead=0; - thisWrite=0; - threadBuffer=NULL; - int rt=MediaPlayer::getInstance()->getMediaBlock(2,streampos,BUFLEN,&thisRead,&threadBuffer); - if (thisRead == 0 && threadBuffer) { - free(threadBuffer); - threadBuffer=NULL; - } - if ((!threadBuffer || thisRead == 0 ) && rt == 0) { - retrycount++; - if (retrycount > MAXTRY) rt=-1; - else { - logger->log("AudioPlayer", Log::DEBUG, "no data read, retrying"); - continue; - } - } - - if (!threadBuffer || thisRead == 0 || rt != 0) { - //OK we count this as end of stream - //hmm --- we should be able to detect if the audio has gone... - logger->log("AudioPlayer", Log::DEBUG, "stream end"); - setRequestedState(S_DONE); - MediaPlayer::getInstance()->closeMediaChannel(2); - retrycount=0; - continue; - } - retrycount=0; - //logger->log("AudioPlayer", Log::DEBUG, "read %ld bytes at pos %ld",thisRead,streampos); - streampos+=thisRead; - } - - threadCheckExit(); - /* - MediaPacket p; - memset(&p,sizeof(p),0); - p.pos_buffer=0; - p.length=thisRead; - MediaPacketList pl; - pl.push_back(p); - audio->PrepareMediaSample(pl,0); - UINT bytesWritten=0; - UINT rt=audio->DeliverMediaSample(threadBuffer,&bytesWritten); - ULONG written=thisRead; - if (rt == 0) - written=bytesWritten; - */ - ULONG written= demuxer->put(threadBuffer + thisWrite, thisRead - thisWrite); - thisWrite+=written; - bytesWritten+=written; - if (thisWrite < thisRead) { - if (written == 0) { - // demuxer is full and can't take anymore - waitTimed(200); - } - } - else { - //logger->log("AudioPlayer", Log::DEBUG, "block written %d", thisWrite); - thisWrite=0; - thisRead=0; - free(threadBuffer); - threadBuffer = NULL; - } - - } - - logger->log("AudioPlayer", Log::DEBUG, "finished"); - MediaPlayer::getInstance()->closeMediaChannel(2); - playerRunnig=false; - return; -} - -int AudioPlayer::waitForSequence(int timeout, int seq) { - time_t starttime=time(NULL)+timeout; - time_t curtime=0; - logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence %d",seq); - int rt=-1; - while ((curtime=time(NULL)) < starttime) { - int cseq=getSequence(); - if (cseq >= seq) { - rt=cseq; - break; - } - //logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence loop"); - MILLISLEEP(100); - } - logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence %d returns %d",seq,rt); - return rt; -} - -int AudioPlayer::getSequence() { - int rt=0; - threadLock(); - rt=sequence; - threadUnlock(); - return rt; -} - - - -void AudioPlayer::threadPostStopCleanup() -{ - if (threadBuffer) - { - delete(threadBuffer); - threadBuffer = NULL; - } - playerRunnig=false; -} - -void AudioPlayer::call(void *) { - threadSignalNoLock(); -} - -void AudioPlayer::timercall(int ref) { - if (ref == 1) { - logger->log("AudioPlayer", Log::DEBUG, "stream end - informing frontend"); - sendFrontendMessage(STREAM_END); - } -} - -//--------------------------- info functions ------------------- - -char * AudioPlayer::getTitle() { - logger->log("AudioPlayer", Log::DEBUG, "getTitle"); - threadLock(); - const id3_tag * tag=demuxer->getId3Tag(); - const char * title=NULL; - char *rt=NULL; - if (tag != NULL) { - title=tag->title; - } - if (title && strlen(title) != 0) { - rt=new char[strlen(title)+1]; - strcpy(rt,title); - rt[strlen(title)]=0; - } - //let the frontend fill in something - threadUnlock(); - return rt; -} - -char * AudioPlayer::getID3Info() { - logger->log("AudioPlayer", Log::DEBUG, "getID3Info"); - threadLock(); - int len=0; - const id3_tag * tag=demuxer->getId3Tag(); - int taglen=0; - if (tag) taglen=tag->stringlen(false); - len+=taglen; - const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo(); - if (info) len+=30; - char * rt=NULL; - if (len > 0) { - char bitrateType='C'; - if (info && info->avrBitrate != info->bitRate) bitrateType='V'; - rt=new char[len]; - if (!tag && info) { - int sr=info->sampleRate/1000; - SNPRINTF(rt,len-1,"%s: %s/L%d %cBR,SR=%d.%02dkBit/s,%s\n",tr("MpegInfo"), - info->mpegVersion,info->mpegLayer,bitrateType,sr,(info->sampleRate/10-sr*100), - info->info); - } - else if (tag && info){ - int sr=info->sampleRate/1000; - char *tmp=new char[taglen+1]; - SNPRINTF(rt,len-1,"%s\n" - "%s: %s/L%d %cBR,SR=%d.%02dkBit/s,%s\n", - tag->toString(tmp,taglen,false), - tr("MpegInfo"), - info->mpegVersion,info->mpegLayer,bitrateType,sr,(info->sampleRate/10-sr*100), - info->info); - delete [] tmp; - } - else if (tag && !info){ - char *tmp=new char[taglen+1]; - SNPRINTF(rt,len-1,"%s\n", - tag->toString(tmp,taglen,false)); - delete [] tmp; - } - rt[len-1]=0; - } - threadUnlock(); - logger->log("AudioPlayer", Log::DEBUG, "getID3Info returns %s",rt); - return rt; -} - -ULONG AudioPlayer::getCurrentTimes(){ - ULONG rt=0; - threadLock(); - if (streampos != 0){ - rt=demuxer->getSecondsFromLen(bytesWritten); - if (rt == 0) { - //we can only guess - rt= bytesWritten/DEFAULT_BITRATE; - } - } - threadUnlock(); - return rt; -} - -ULONG AudioPlayer::getSonglen(){ - ULONG rt=0; - threadLock(); - const DemuxerAudio::vbrInfo * vbr=demuxer->getVBRINfo(); - if (vbr) rt=vbr->fileSeconds; - else { - if (lenInBytes != 0) { - rt=demuxer->getSecondsFromLen(lenInBytes); - if (rt == 0) { - //we can only guess - rt= lenInBytes/DEFAULT_BITRATE; - } - } - } - threadUnlock(); - return rt; -} - -int AudioPlayer::getCurrentBitrate(){ - int rt=DEFAULT_BITRATE; - threadLock(); - const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo(); - if (info) rt=info->bitRate; - threadUnlock(); - return rt; -} diff --git a/audioplayer.h b/audioplayer.h deleted file mode 100644 index f39df37..0000000 --- a/audioplayer.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - Copyright 2004-2006 Chris Tallon, Andreas Vogel - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef AUDIOPLAYER_H -#define AUDIOPLAYER_H - -#include -#include -#ifndef WIN32 -#include -#endif -#include - -#include "audio.h" -#include "input.h" -#include "vdr.h" -#include "callback.h" -#include "message.h" -#include "messagequeue.h" -#include "thread.h" -#include "afeed.h" -#include "timers.h" - -#ifdef WIN32 -#include "threadwin.h" -#else -#include "threadp.h" -#endif - - -class Boxx; -class DemuxerAudio; -class MediaURI; - - -class AudioPlayer : public Thread_TYPE, public Callback, public TimerReceiver -{ - public: - //the instance method to create the - //player instance - only call thie for - //the first time in the main thread (no lock!) - //later you can change the view the player is connect with - //a view that "goes" should call getInstance(NULL,false) to detach - //the last media view should shutdown the player - static AudioPlayer * getInstance(Boxx * frontend, bool create=true); - //start the player thread - void run(); - - //is the player still running? - bool isPlayerRunning(); - - void shutdown(); - - //each of the commands works as a request - //only after getSequence returned the same sequence as those commands this is - //handled by the player and getError is valid - int play(const MediaURI *uri); - //stop the player without shutting it down - int stop(); - int pause(); - int unpause(); - int fastForward(); - int fastBackward(); - int jumpToPercent(double percent); - int skipForward(int sec); - int skipBackward(int sec); - - //info functions for frontend - //delete provided String afterwards - //get the played title from ID3 Tag - or NULL - char * getTitle(); - //get info - //multi line String containing ID3 infos - char * getID3Info(); - - //wait for a particular sequence to be handled - //timeout in s, returnes current sequence, -1 on timeout - int waitForSequence(int timeout, int sequence); - int getSequence(); - - //info functions - - //get current position in s - ULONG getCurrentTimes(); - //get song len in s - ULONG getSonglen(); - //current bitrate - int getCurrentBitrate(); - - - virtual void call(void * caller); - - UCHAR getState() ; - - const static UCHAR S_PLAY = 1; - const static UCHAR S_PAUSE = 2; - const static UCHAR S_POSITION = 3; - //player finished a song - no reset, next will follow - const static UCHAR S_DONE=5; - const static UCHAR S_STOP = 6; - const static UCHAR S_ERROR = 8; - const static UCHAR S_FF = 9; - const static UCHAR S_BACK = 10; - - //message parameters for frontend messages - const static ULONG CONNECTION_LOST=1; - const static ULONG STREAM_END=2; - const static ULONG STREAM_ERR=3; - const static ULONG STATUS_CHANGE=4; //some info has been changed - const static ULONG NEW_SONG=5; //some info has been changed - const static ULONG SHORT_UPDATE=6; //timer info update - const static ULONG EXTERN1=7; //for other users as parameter to player event - - virtual void timercall(int reference); - - protected: - void threadMethod(); - void threadPostStopCleanup(); - - private: - //to guess lengthes if the demux does not know - const static ULONG DEFAULT_BITRATE=128000; - AudioPlayer(Boxx *frontend); - virtual ~AudioPlayer(); - static AudioPlayer * instance; - bool playerRunnig; - Audio* audio; - VDR* vdr; - Log* logger; - - DemuxerAudio *demuxer; - AFeed afeed; - - //feeder control - const static int FEEDER_START=1; - const static int FEEDER_STOP=2; - const static int FEEDER_PAUSE=3; - const static int FEEDER_UNPAUSE=4; - void controlFeeder(int action) ; - int feederState; - - //synchronized get/set methods for states - int setRequestedState(UCHAR st); - void setState(UCHAR st); - - //to be called from within the thread - UCHAR checkState(); - - //variables used by the thread - ULONG thisWrite; - ULONG thisRead; - bool running; - - UCHAR *threadBuffer; - UCHAR state; - UCHAR requestState; - ULLONG streampos; - ULLONG lenInBytes; - ULLONG bytesWritten; - ULLONG requestedStreampos; - - int skipfactor; - //the buffer len in bytes - const static int BUFLEN=50*1024; - Boxx *frontend; - //requested sequence - int requestedSequence; - //handled sequence - int sequence; - //startplay sequence - int currentPlaySequence; - //sequence that is changed for each new filename - int playSequence; - //can we position? - bool canPosition; - - - MediaURI *uri; - int openFile(); - - void sendFrontendMessage(ULONG para); - - void waitTimed(int ms); - - -}; - -#endif - diff --git a/audiowin.cc b/audiowin.cc deleted file mode 100644 index 7e7a214..0000000 --- a/audiowin.cc +++ /dev/null @@ -1,727 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "audiowin.h" -#include "videowin.h" -#include "vdr.h" -#include "wtabbar.h" -#include "wwinaudiofilter.h" -#include "wwinmp3audiofilter.h" -#include "i18n.h" - - - - -AudioWin::AudioWin() -{ - initted = 0; - firstsynched=false; - winvolume=0; - volume=20; -audiofilterselected=-1; - mp3audiofilterselected=-1; - aud_type=Audio::MPEG2_PES; - -} - -AudioWin::~AudioWin() -{ - - int i; - for (i=0;isetAudioStreamType(type); - aud_type=type; - if (!initted) return 0; - return 1; -} - -int AudioWin::setChannel() -{ - if (!initted) return 0; - return 1; -} - -int AudioWin::setSource() -{ - if (!initted) return 0; - return 1; -} - -int AudioWin::sync() -{ - if (!initted) return 0; - return 1; -} - -int AudioWin::play() -{ - if (!initted) return 0; - firstsynched=false; - return ((VideoWin*)Video::getInstance())->dsplay(); - -} - -int AudioWin::stop() -{ - if (!initted) return 0; - return ((VideoWin*)Video::getInstance())->dsstop(); -} - -int AudioWin::pause() -{ - if (!initted) return 0; - return ((VideoWin*)Video::getInstance())->dspause(); -} - -int AudioWin::unPause() -{ - if (!initted) return 0; - return ((VideoWin*)Video::getInstance())->dsunPause(); -} - -int AudioWin::reset() -{ - - if (!initted){return 0;} - return ((VideoWin*)Video::getInstance())->dsreset(); -} - -int AudioWin::setVolume(int tvolume) -{ - // parameter: 0 for silence, 20 for full - if ((tvolume < 0) || (tvolume > 20)) return 0; - winvolume=((tvolume-20)*100*30)/20; - if (tvolume==0) winvolume=-10000; - ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume); - - - return 1; -} - -int AudioWin::mute() -{ - if (!initted) return 0; - ((VideoWin*)Video::getInstance())->SetAudioState(false); - ((VideoWin*)Video::getInstance())->SetAudioVolume(-10000); - return 1; -} - -int AudioWin::unMute() -{ - if (!initted) return 0; - ((VideoWin*)Video::getInstance())->SetAudioState(true); - ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume); - return 1; -} - -void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) -{ - mediapacket = mplist.front(); -} - -void AudioWin::initFilterDatabase() -{ - /* This method should determine all availiable DirectShow Filters */ - IFilterMapper2* filtmap=NULL; - HRESULT result; - result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC, - IID_IFilterMapper2,(void**)&filtmap); - if (result != S_OK) - { - Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!"); - return; - } - /* Wishlist, what Mediatypes do we want */ - GUID mtypesin[]={MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO, - /*MEDIATYPE_Audio,MEDIASUBTYPE_MPEG1Payload,*/ - MEDIATYPE_Audio,MEDIASUBTYPE_DOLBY_AC3, - MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3_SPDIF}; - IEnumMoniker *myenum; - result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1, - TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL); - if (result != S_OK) - { - filtmap->Release(); - Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!"); - return; - } - ULONG gethowmany; - IMoniker * moni; - while(myenum->Next(1,&moni,&gethowmany)==S_OK) - { - AudioFilterDesc desc; - ZeroMemory(&desc,sizeof(desc)); - - LPOLESTR string; - moni->GetDisplayName(0,0,&string); - desc.displayname=new char[wcslen(string)+1]; - wcstombs(desc.displayname,string,wcslen(string)+1); - CoTaskMemFree(string); - IPropertyBag *bag; - if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK) - { - VARIANT vari; - VariantInit(&vari); - result = bag->Read(L"FriendlyName",&vari,NULL); - if (result == S_OK) - { - desc.friendlyname=new char[wcslen(vari.bstrVal)+1]; - wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1); - } - VariantClear(&vari); - bag->Release(); - - } - - - audiofilterlist.push_back(desc); - - - - moni->Release(); - // bctx->Release(); - } - int i; - audiofilterselected=-1; - myenum->Release(); - filtmap->Release(); -} - -void AudioWin::initMp3FilterDatabase() -{ - /* This method should determine all availiable DirectShow Filters */ - IFilterMapper2* filtmap=NULL; - HRESULT result; - result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC, - IID_IFilterMapper2,(void**)&filtmap); - if (result != S_OK) - { - Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!"); - return; - } - /* Wishlist, what Mediatypes do we want */ - GUID mtypesin[]={MEDIATYPE_Audio,MEDIATYPE_WaveFmt_Mpeg1Layer3, - MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO}; - IEnumMoniker *myenum; - result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1, - TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL); - if (result != S_OK) - { - filtmap->Release(); - Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!"); - return; - } - ULONG gethowmany; - IMoniker * moni; - while(myenum->Next(1,&moni,&gethowmany)==S_OK) - { - AudioFilterDesc desc; - ZeroMemory(&desc,sizeof(desc)); - - LPOLESTR string; - moni->GetDisplayName(0,0,&string); - desc.displayname=new char[wcslen(string)+1]; - wcstombs(desc.displayname,string,wcslen(string)+1); - CoTaskMemFree(string); - IPropertyBag *bag; - if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK) - { - VARIANT vari; - VariantInit(&vari); - result = bag->Read(L"FriendlyName",&vari,NULL); - if (result == S_OK) - { - desc.friendlyname=new char[wcslen(vari.bstrVal)+1]; - wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1); - } - VariantClear(&vari); - bag->Release(); - - } - - - mp3audiofilterlist.push_back(desc); - - - - moni->Release(); - // bctx->Release(); - } - int i; - mp3audiofilterselected=-1; - myenum->Release(); - filtmap->Release(); -} - -bool AudioWin::loadOptionsFromServer(VDR* vdr) -{ - char *name=vdr->configLoad("DirectShow","AudioFilter"); - - if (name != NULL) - { - for (int i = 0;i configLoad("DirectShow","Mp3AudioFilter"); - - if (name != NULL) - { - for (int i = 0;i configSave("DirectShow", - "AudioFilter",audiofilterlist[audiofilterselected].displayname); - } - if (mp3audiofilterselected!=-1) { - VDR::getInstance()->configSave("DirectShow", - "Mp3AudioFilter",mp3audiofilterlist[mp3audiofilterselected].displayname); - } - return true; -} - -UINT AudioWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos) -{ - DeliverMediaPacket(mediapacket, buffer, samplepos); - if (*samplepos == mediapacket.length) { - *samplepos = 0; - return 1; - } - else return 0; -} - -UINT AudioWin::DeliverMediaPacket(const MediaPacket packet, - UCHAR* buffer, - UINT *samplepos) -{ - - /*First Check, if we have an audio sample*/ - VideoWin *vw=(VideoWin*)Video::getInstance(); - if (!vw->isdsinited()) return 0; - if (vw->InIframemode()) { - samplepos=0; - MILLISLEEP(10); - return 0; //Not in iframe mode! - } - IMediaSample* ms=NULL; - REFERENCE_TIME reftime1=0; - REFERENCE_TIME reftime2=0; - - UINT headerstrip=0; - if (packet.disconti) { - firstsynched=false; - vw->DeliverAudioMediaSample(); - } - - if (packet.type!=vw->lastAType()){//Format Change //Push data out ! - firstsynched=false; - vw->DeliverAudioMediaSample(); - } - - - - /*Inspect PES-Header */ -/* UINT header_length=buffer[(packet.pos_buffer+8)%bufferlength]+8/*is this right*; -*/ - if (*samplepos==0 && packet.type!=MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader - headerstrip=buffer[packet.pos_buffer+8]+9; - if (packet.type == MPTYPE_AC3) headerstrip+=4; //skip ac3 bytes - *samplepos+=headerstrip; - if ( packet.synched ) { - vw->DeliverAudioMediaSample();//write out old data - reftime1=packet.presentation_time; - reftime2=reftime1+1; - firstsynched=true; - } else { - if (!firstsynched) {// - *samplepos=packet.length;//if we have not processed at least one - return packet.length;//synched packet ignore it! - } - } - } - BYTE *ms_buf; - UINT ms_length; - UINT ms_pos; - UINT haveToCopy; - if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample - //samplepos=0; - //MILLISLEEP(10); - return *samplepos; - } - ms_pos=ms->GetActualDataLength(); - ms_length=ms->GetSize(); - haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos); - if ((ms_length-ms_pos)<1) { - vw->DeliverAudioMediaSample(); //we are full! - if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample - //samplepos=0; - //MILLISLEEP(10); - return *samplepos; - } - ms_pos=ms->GetActualDataLength(); - ms_length=ms->GetSize(); - haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos); - } - ms->GetPointer(&ms_buf); - - - if (ms_pos==0) {//will only be changed on first packet - if (packet.disconti) { - ms->SetDiscontinuity(TRUE); - } else { - ms->SetDiscontinuity(FALSE); - } - if (packet.synched) { - ms->SetSyncPoint(TRUE); - ms->SetTime(&reftime1,&reftime2); - - //ms->SetTime(NULL,NULL); - ms->SetMediaTime(NULL, NULL); - if (reftime1<0) ms->SetPreroll(TRUE); - else ms->SetPreroll(FALSE); - }else { - ms->SetSyncPoint(FALSE); - ms->SetTime(NULL,NULL); - ms->SetMediaTime(NULL, NULL); - ms->SetPreroll(FALSE); - // ms->SetSyncPoint(TRUE); - } - } - if (packet.type!=vw->lastAType()) { - vw->changeAType(packet.type,ms); - ms->SetDiscontinuity(TRUE); - } - - - memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy); - - ms->SetActualDataLength(haveToCopy+ms_pos); - - *samplepos+=haveToCopy; - - return haveToCopy+headerstrip; - -} - -int AudioWin::dsInitAudioFilter(IGraphBuilder* dsgraphbuilder) -{ - HRESULT hres; - IFilterGraph2*fg2=NULL; - VideoWin *vw=(VideoWin*)Video::getInstance(); - if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK) - { - Log::getInstance()->log("AudiooWin", Log::WARN , "Failed querying for FilterGraph2 Interface!"); - return 0; - } - IBaseFilter*audiofilter; - if (aud_type!=Audio::MP3) { - audiofilter = getAudioFilter(); - } else { - audiofilter = getMp3AudioFilter(); - } - if (dsgraphbuilder->AddFilter(audiofilter,NULL) != S_OK) - { - Log::getInstance()->log("AudioWin", Log::WARN , "Failed adding Video Filter!"); - return 0; - } - IEnumPins *pinenum=NULL; - bool error=false; - if (audiofilter->EnumPins(&pinenum) == S_OK) - { - IPin *current=NULL; - ULONG fetch=0; - bool firststep=false; - while (pinenum->Next(1,¤t,&fetch)==S_OK) - { - PIN_DIRECTION dir; - if (current->QueryDirection(&dir)==S_OK) - { - if (dir == PINDIR_INPUT) - { - if (vw->getSourceFilter()->GetAudioPin()->Connect(current,NULL)==S_OK) - { - current->Release(); - firststep=true; - break; - } - } - } - current->Release(); - } - if (firststep==false) - { - Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable input!"); - audiofilter->Release(); - return 0; - } - bool secondstep=false; - pinenum->Reset(); - while (pinenum->Next(1,¤t,&fetch)==S_OK) - { - PIN_DIRECTION dir; - if (current->QueryDirection(&dir)==S_OK) - { - if (dir == PINDIR_OUTPUT) - { - - if (fg2->RenderEx((IPin*)current/*video*/, - 0,NULL) ==S_OK) - { - current->Release(); - secondstep=true; - break; - } - } - } - current->Release(); - } - if (secondstep==false) - { - Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable output!"); - audiofilter->Release(); - - return 0; - } - - audiofilter->Release(); - pinenum->Release(); - - } - - - - fg2->Release(); - return 1; -} - - -IBaseFilter *AudioWin::getAudioFilter() -{ - IBaseFilter *curfilter= NULL; - bool notset=false; - if (audiofilterselected == -1) - { - int i; - for (i = 0;i BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK) - { - if (curfilter != NULL && notset) - { - VDR *vdr=VDR::getInstance(); - if (vdr != NULL) - { - vdr->configSave("DirectShow","AudioFilter", - audiofilterlist[audiofilterselected].displayname); - } - } - - moni->Release(); - delete [] name; - bindctx->Release(); - return curfilter; - } - bindctx->Release(); - delete [] name; - return NULL; - } - return NULL; -} - -IBaseFilter *AudioWin::getMp3AudioFilter() -{ - IBaseFilter *curfilter= NULL; - bool notset=false; - if (mp3audiofilterselected == -1) - { - int i; - for (i = 0;i BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK) - { - if (curfilter != NULL && notset) - { - VDR *vdr=VDR::getInstance(); - if (vdr != NULL) - { - vdr->configSave("DirectShow","Mp3AudioFilter", - mp3audiofilterlist[mp3audiofilterselected].displayname); - } - } - - moni->Release(); - delete [] name; - bindctx->Release(); - return curfilter; - } - bindctx->Release(); - delete [] name; - return NULL; - } - return NULL; -} - - -bool AudioWin::addOptionPagesToWTB(WTabBar *wtb) -{ - Boxx *box=new WWinAudioFilter(); - wtb->addTab(tr("Audio Filter"), box); - - - box=new WWinMp3AudioFilter(); - wtb->addTab(tr("Mp3 Audio Filter"), box); - - - return true; -} - -const AudioFilterDescList *AudioWin::getAudioFilterList(int &selected) -{ - selected=audiofilterselected; - return &audiofilterlist; -} - -const AudioFilterDescList *AudioWin::getMp3AudioFilterList(int &selected) -{ - selected=mp3audiofilterselected; - return &mp3audiofilterlist; -} -bool AudioWin::selectMp3AudioFilter(int filter) -{ - mp3audiofilterselected=filter; - return true; - -} - -bool AudioWin::selectAudioFilter(int filter) -{ - audiofilterselected=filter; - return true; - -} - -long long AudioWin::SetStartOffset(long long curreftime, bool *rsync){ - VideoWin *vw=(VideoWin*)Video::getInstance(); - return vw->SetStartAudioOffset(curreftime,rsync); -} - -void AudioWin::ResetTimeOffsets() { - VideoWin *vw=(VideoWin*)Video::getInstance(); - vw->ResetTimeOffsets(); -} - -bool AudioWin::supportsAc3(){ - VideoWin *vw=(VideoWin*)Video::getInstance(); - return vw->supportsAc3(); -} - -#ifdef DEV -int AudioWin::test() -{ - return 0; -} -#endif - - - diff --git a/audiowin.h b/audiowin.h deleted file mode 100644 index 44a179e..0000000 --- a/audiowin.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef AUDIOWIN_H -#define AUDIOWIN_H - -#include "defines.h" -#include "oldlog.h" -#include "audio.h" -#include -#include -#include "dssourcefilter.h" - -#include - -struct AudioFilterDesc { - char * displayname; - char * friendlyname; -}; -typedef std::vector AudioFilterDescList; - -class AudioWin : public Audio -{ - public: - AudioWin(); - ~AudioWin(); - - int init(UCHAR streamType); - int shutdown(); - - int setStreamType(UCHAR streamType); - int setChannel(); - int setSource(); - int sync(); - int play(); - int stop(); - int pause(); - int unPause(); - int reset(); - int setVolume(int volume); - int mute(); - int unMute(); - int write(char *buf, int len); - - bool loadOptionsFromServer(VDR* vdr); - bool saveOptionstoServer(); - bool addOptionPagesToWTB(WTabBar *wtb); - - // Writing Data to Audiodevice - virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); - virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos); - UINT DeliverMediaPacket(MediaPacket packet, UCHAR* buffer, UINT *samplepos); - - int dsInitAudioFilter(IGraphBuilder* dsgraphbuilder); - const AudioFilterDescList *getAudioFilterList(int &selected); - bool selectAudioFilter(int filter); - - const AudioFilterDescList *getMp3AudioFilterList(int &selected); - bool selectMp3AudioFilter(int filter); - - virtual bool supportsAc3(); - virtual bool maysupportAc3(){return true;} // We are not sure maybe we support this, allows the player to select ac3, if there is no other option - - virtual bool streamTypeSupported(int streamtype) - { - switch (streamtype) { - case 0x6A: - case 3: - case 4: - return true; - default: - return false; - }; - } - - - private: - MediaPacket mediapacket; - public: - virtual long long SetStartOffset(long long curreftime, bool *rsync); - virtual void ResetTimeOffsets(); - -private: - IBaseFilter *getAudioFilter(); - IBaseFilter *getMp3AudioFilter(); - void initFilterDatabase(); - void initMp3FilterDatabase(); - AudioFilterDescList audiofilterlist; - AudioFilterDescList mp3audiofilterlist; - int audiofilterselected; - int mp3audiofilterselected; - bool firstsynched; - long winvolume; - UCHAR aud_type; -#ifdef DEV - int test(); -#endif -}; - -#endif - diff --git a/bitmap.cc b/bitmap.cc deleted file mode 100644 index 7947994..0000000 --- a/bitmap.cc +++ /dev/null @@ -1,139 +0,0 @@ -/* - Copyright 2008 Mark Calderbank - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "bitmap.h" - - -DisplayRegion::DisplayRegion() -{ - framewidth=720; - frameheight=576; - windowx=0; - windowy=0; - windoww=719; - windowh=575; -} - -Palette::Palette(UCHAR tBpp) -{ - numColours = 0; - setBpp(tBpp); -} - -void Palette::argb2yrba(ULONG argb, UCHAR& y, UCHAR& cr, UCHAR& cb, UCHAR& a) -{ - a = static_cast((argb & 0xFF000000) >> 24); - int r = (argb & 0x00FF0000) >> 16; - int g = (argb & 0x0000FF00) >> 8; - int b = (argb & 0x000000FF); - y = static_cast((1052*r + 2065*g + 401*b + 4096*16 + 2048) / 4096); - cr = static_cast((1799*r - 1508*g - 291*b + 4096*128 + 2048) / 4096); - cb = static_cast((-608*r - 1191*g + 1799*b + 4096*128 + 2048) / 4096); -} - -ULONG Palette::yrba2argb(UCHAR y, UCHAR cr, UCHAR cb, UCHAR a) -{ - int r, g, b; - r = (4769*(y-16) + 6537*(cr-128) + 2048) / 4096; - g = (4769*(y-16) - 3329*(cr-128) - 1604*(cb-128) + 2048) / 4096; - b = (4769*(y-16) + 8263*(cb-128) + 2048) / 4096; - if (r < 0) r = 0; - if (r > 255) r = 255; - if (g < 0) g = 0; - if (g > 255) g = 255; - if (b < 0) b = 0; - if (b > 255) b = 255; - return (a << 24) + (r << 16) + (g << 8) + b; -} - -void Palette::setBpp(UCHAR tBpp) -{ - bpp = tBpp; - if (bpp > MAX_DEPTH) bpp = MAX_DEPTH; - maxColours = 1 << bpp; - if (numColours > maxColours) numColours = maxColours; - colour.resize(maxColours,0xFF000000); - Y.resize(maxColours,16); - Cr.resize(maxColours,128); - Cb.resize(maxColours,128); - A.resize(maxColours,255); -} - -void Palette::setColour(UCHAR index, ULONG tColour) -{ - if (index >= maxColours) return; - if (index >= numColours) numColours = index + 1; - colour[index] = tColour; - argb2yrba(tColour, Y[index], Cr[index], Cb[index], A[index]); -} - -void Palette::setYCrCbA(UCHAR index, UCHAR tY, UCHAR tCr, UCHAR tCb, UCHAR tA) -{ - if (index >= maxColours) return; - if (index >= numColours) numColours = index + 1; - Y[index] = tY; Cr[index] = tCr; Cb[index] = tCb; A[index] = tA; - colour[index] = yrba2argb(tY, tCr, tCb, tA); -} - -Bitmap::Bitmap(UINT tWidth, UINT tHeight, UCHAR tBpp) -{ - setSize(tWidth, tHeight); - palette.setBpp(tBpp); -} - -void Bitmap::setSize(UINT tWidth, UINT tHeight) -{ - if (width == tWidth && height == tHeight) return; - width = tWidth; height = tHeight; - if (width == 0 || height == 0) - bitmap.clear(); - else - bitmap.assign(width * height, 0); -} - -bool Bitmap::setIndex(UINT x, UINT y, UCHAR index) -{ - if (x <= width && y <= height) - { - bitmap[x + y*width] = index; - return true; - } - else return false; -} - -UCHAR Bitmap::getIndex(UINT x, UINT y) const -{ - if (x > width || y > height) - return 0; - else - return bitmap[x + y*width]; -} - -ULONG Bitmap::getColour(UINT x, UINT y) const -{ - if (x > width || y > height) - return 0; - else - return palette.getColour(bitmap[x + y*width]); -} - -void Bitmap::setAllIndices(UCHAR index) -{ - bitmap.assign(width * height, index); -} diff --git a/bitmap.h b/bitmap.h deleted file mode 100644 index f59b5a5..0000000 --- a/bitmap.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright 2008 Mark Calderbank - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef BITMAP_H -#define BITMAP_H - -#include "defines.h" -#include - -class DisplayRegion -{ - public: - DisplayRegion(); - UINT windowx, windowy, windoww, windowh; - UINT framewidth,frameheight; -}; - -class Palette -{ - public: - Palette(UCHAR tBpp = 8); - UCHAR getBpp() const { return bpp; } - void reset() { numColours = 0; } - void setBpp(UCHAR tBpp); - ULONG getColour(UCHAR index) const { return index < maxColours ? colour[index] : 0; } - void setColour(UCHAR index, ULONG tColour); - void setYCrCbA(UCHAR index, UCHAR tY, UCHAR tCr, UCHAR tCb, UCHAR tA); - const std::vector& getColourVector() const { return colour; } - const std::vector& getYVector() const { return Y; } - const std::vector& getCrVector() const { return Cr; } - const std::vector& getCbVector() const { return Cb; } - const std::vector& getAVector() const { return A; } - UINT getNumColours() const { return numColours; } - private: - const static UINT MAX_DEPTH = 8; - std::vector colour; - std::vector Y; - std::vector Cr; - std::vector Cb; - std::vector A; - UCHAR bpp; - UINT maxColours, numColours; - void argb2yrba(ULONG argb, UCHAR& y, UCHAR& cr, UCHAR& cb, UCHAR& a); - ULONG yrba2argb(UCHAR y, UCHAR cr, UCHAR cb, UCHAR a); -}; - -class Bitmap -{ - private: - std::vector bitmap; - UINT width, height; - public: - Bitmap(UINT tWidth = 0, UINT tHeight = 0, UCHAR tBpp = 8); - Palette palette; - UINT getWidth() const { return width; } - UINT getHeight() const { return height; } - UCHAR getIndex(UINT x, UINT y) const; - ULONG getColour(UINT x, UINT y) const; - const std::vector & rawData() const { return bitmap; } - void setSize(UINT tWidth, UINT tHeight); - bool setIndex(UINT x, UINT y, UCHAR index); - void setAllIndices(UCHAR index); -}; - -#endif diff --git a/bogl.h b/bogl.h deleted file mode 100644 index 9dc98a3..0000000 --- a/bogl.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef BOGL_H -#define BOGL_H - -/* - * This header file is here for font .c files that are created with the - * bdftobogl utility that comes with bogl. - */ - -typedef struct bogl_font { - char *name; /* Font name. */ - int height; /* Height in pixels. */ - int spacing; /* Vertical spacing in pixels. */ - unsigned long *content; /* 32-bit right-padded bitmap array. */ - short *offset; /* 256 offsets into content. */ - unsigned char *width; /* 256 character widths. */ -} osd_font_t; - -#endif /* BOGL_H */ diff --git a/boxstack.cc b/boxstack.cc deleted file mode 100644 index afd76ef..0000000 --- a/boxstack.cc +++ /dev/null @@ -1,572 +0,0 @@ - -/* - Copyright 2004-2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#include "log.h" -#include "messagequeue.h" -#include "input.h" -#include "osd.h" - -#include "boxstack.h" - -static const char* TAG = "BoxStack"; - -BoxStack* BoxStack::instance = NULL; - -BoxStack::BoxStack() -{ - if (instance) return; - instance = this; - osd = Osd::getInstance(); -} - -BoxStack::~BoxStack() -{ - instance = NULL; -} - -BoxStack* BoxStack::getInstance() -{ - return instance; -} - -int BoxStack::init() -{ - if (initted) return 0; - initted = 1; - - return 1; -} - -int BoxStack::shutdown() -{ - if (!initted) return 0; - removeAll(); - initted = 0; - return 1; -} - -void BoxStack::removeAll() -{ - removeAllExceptWallpaper(); - if (numBoxes == 1) remove(boxes[0]); -} - -int BoxStack::addVideoDisplay(Boxx* box,VideoDisplay vd) -{ - boxLock.lock(); - videoStack.push(std::pair(box,vd)); - boxLock.unlock(); - Video::getInstance()->setVideoDisplay(vd); - return 1; -} - -int BoxStack::add(Boxx* v) -{ - if (!initted) return 0; - LogNT::getInstance()->debug(TAG, "add called"); - boxLock.lock(); - LogNT::getInstance()->debug(TAG, "Locked for add"); - - if (numBoxes == 16) - { //Error - LogNT::getInstance()->error(TAG, "More than 16 boxes! Unlocked for add"); - boxLock.unlock(); - return 0; - } - boxes[numBoxes++] = v; - boxLock.unlock(); - VideoDisplay vd; - if (v->getVideoDisplay(vd)) { - LogNT::getInstance()->debug(TAG, "Add video display"); - addVideoDisplay(v,vd); - } - - - - LogNT::getInstance()->debug(TAG, "Unlocked for add"); - - return 1; -} - -// ---------------------------------------------------- REMOVE CODE - -int BoxStack::remove(Boxx* toDelete) -{ - if (!initted) return 0; - VideoDisplay *display = NULL; - - boxLock.lock(); - LogNT::getInstance()->debug(TAG, "Locked for remove"); - - if (numBoxes == 0) - { - boxLock.unlock(); - LogNT::getInstance()->error(TAG, "Unlocked for remove numBoxes == 0"); - return 0; - } - -// LogNT::getInstance()->debug(TAG, "entering remove, numBoxes={}", numBoxes); - - int i; - - if (toDelete == NULL) - { - toDelete = boxes[numBoxes-1]; - i = numBoxes - 1; - } - else - { - // to be deleted box is more likely to be at the top - for (i = numBoxes-1; i >= 0; i--) - { -// LogNT::getInstance()->debug(TAG, "todel: {}, i={}, boxes[i]={}", (void*)toDelete, i, (void*)boxes[i]); - if (boxes[i] == toDelete) break; - } - - if (i == -1) - { - // not a Box we have! - // FIXME - boxLock.unlock(); - LogNT::getInstance()->error(TAG, "Unlocked for remove - no boxx deleted"); - return 0; - } - } - - boxLock.unlock(); - - toDelete->preDelete(); - - boxLock.lock(); - - //LogNT::getInstance()->debug(TAG, "Starting repaintRevealed loop"); - RegionList rl; - boxSplit(boxes[i]->area, i + 1, numBoxes, 1, rl); - while(!rl.empty()) - { - repaintRevealed(i, rl.front()); - rl.pop_front(); - } - //LogNT::getInstance()->debug(TAG, "Done repaintRevealed loop"); - - // Shift the boxes on top down one - --numBoxes; - for(int j = i; j < numBoxes; j++) boxes[j] = boxes[j+1]; - - // If there is only the wallpaper left signal command - if (numBoxes == 1) - { - Message* m = new Message(); - m->p_to = Message::CONTROL; - m->message = Message::LAST_VIEW_CLOSE; - MessageQueue::getInstance()->postMessage(m); - } - - if (!videoStack.empty() && videoStack.top().first==toDelete) { - videoStack.pop(); - if (!videoStack.empty()) display=&videoStack.top().second; - } - boxLock.unlock(); - LogNT::getInstance()->debug(TAG, "Unlocked for remove"); - - // Delete the box - //AVO: do this delete outside the lock to allow for recursive calls within the destructor - // as this box is not in the stack any more, there is no chance for a second delete - LogNT::getInstance()->debug(TAG, "remove: going to delete boxx {}, num {}", static_cast(toDelete), numBoxes); - delete toDelete; - - osd->doRender(); - - if (display) { - LogNT::getInstance()->debug(TAG, "setVideoDisplay {} {} {} {} {} {}", display->mode, display->fallbackMode, - display->x, display->y, display->width, display->height); - Video::getInstance()->setVideoDisplay(*display); - } - - return 1; -} - -void BoxStack::redrawAllBoxes() -{ - boxLock.lock(); - - for (int z = 0; z < numBoxes; z++) - { - boxes[z]->draw(); - } - - boxLock.unlock(); - update(NULL,NULL); // should blt all -} - -void BoxStack::update(Boxx* toUpdate, const Region* regionToUpdate) -{ -// LogNT::getInstance()->debug(TAG, "Update called"); - if (!initted) return; // it is allowed to call this before init - boxLock.lock(); -// LogNT::getInstance()->debug(TAG, "Locked for update"); - - // Get the z index of the box - int z = 0; - if (toUpdate) - { - for (z = 0; z < numBoxes; z++) - { - if (boxes[z] == toUpdate) break; - } - - if (z == numBoxes) - { - // not a Box we have! - boxLock.unlock(); - LogNT::getInstance()->error(TAG, "Unlocked for update! box not inside boxstack"); - return; - } - } - else - { - toUpdate = boxes[0]; - } - - if (!toUpdate) { - boxLock.unlock(); - LogNT::getInstance()->debug(TAG, "Unlocked for update, no box present"); - return ; - } - - // get the region for the whole box, could be less than that - // for smaller updates - - Region r = toUpdate->area; - - if (regionToUpdate) - { - // Can be null if the whole box should be updated - // If this is given the numbers are relative to the size of the box, not the screen - - r.x += regionToUpdate->x; - r.y += regionToUpdate->y; - r.w = regionToUpdate->w; - r.h = regionToUpdate->h; - } - - RegionList rl; - - Region r2; - boxSplit(r, z+1, numBoxes, 1, rl); - while(!rl.empty()) - { - r2 = rl.front(); - r2.z = z; - boxes[z]->blt(r2); - rl.pop_front(); - } - - boxLock.unlock(); -// LogNT::getInstance()->debug(TAG, "Unlocked for update"); -} - -void BoxStack::repaintRevealed(int x, Region r) -{ - RegionList rl; - boxSplit(r, x - 1, -1, -1, rl); - - Region r2; - while(!rl.empty()) - { - r2 = rl.front(); - boxes[r2.z]->blt(r2); - rl.pop_front(); - } -} - -void BoxStack::boxSplit(Region r, int start, int end, int direction, RegionList& rl) -{ -// printf("Y= S=%i E=%i D=%i: Boxsplit: %i %i %i %i\n", start, end, direction, r.x, r.y, r.w, r.h); - - for(int z = start; z != end; z += direction) - { - if (r.overlappedBy(boxes[z]->area)) - { -// printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z); - - int top = r.y; - int btm = r.y2(); - - if (boxes[z]->area.y > r.y) - { -// printf("Z=%i S=%i E=%i D=%i: Case 1 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h); - top = boxes[z]->area.y; - Region newR; - newR.x = r.x; - newR.y = r.y; - newR.w = r.w; - newR.h = boxes[z]->area.y - r.y; - boxSplit(newR, z + direction, end, direction, rl); - - if (direction == -1) - { - Region newR2; - newR2.x = r.x; - newR2.y = boxes[z]->area.y; - newR2.w = r.w; - newR2.h = r.h - newR.h; - boxSplit(newR2, z, end, -1, rl); - return; - } - } - - if (boxes[z]->area.y2() < r.y2()) - { -// printf("Z=%i S=%i E=%i D=%i: Case 2 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h); - btm = boxes[z]->area.y2(); - Region newR; - newR.x = r.x; - newR.y = boxes[z]->area.y2() + 1; - newR.w = r.w; - newR.h = r.y2() - newR.y + 1; - boxSplit(newR, z + direction, end, direction, rl); - - if (direction == -1) - { - Region newR2; - newR2.x = r.x; - newR2.y = r.y; - newR2.w = r.w; - newR2.h = r.h - newR.h; - boxSplit(newR2, z, end, -1, rl); - return; - } - } - - if (boxes[z]->area.x > r.x) - { -// printf("Z=%i S=%i E=%i D=%i: Case 3 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h); - Region newR; - newR.x = r.x; - newR.y = top; - newR.w = boxes[z]->area.x - r.x; - newR.h = btm - top + 1; - boxSplit(newR, z + direction, end, direction, rl); - - if (direction == -1) - { - Region newR2; - newR2.x = r.x + newR.w; - newR2.y = r.y; - newR2.w = r.w - newR.w; - newR2.h = r.h; - boxSplit(newR2, z, end, -1, rl); - return; - } - } - - if (boxes[z]->area.x2() < r.x2()) - { -// printf("Z=%i S=%i E=%i D=%i: Case 4 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, boxes[z]->area.x, boxes[z]->area.y, boxes[z]->area.w, boxes[z]->area.h); - Region newR; - newR.x = boxes[z]->area.x2() + 1; - newR.y = top; - newR.w = r.x2() - newR.x + 1; - newR.h = btm - top + 1; - boxSplit(newR, z + direction, end, direction, rl); - - if (direction == -1) - { - Region newR2; - newR2.x = r.x; - newR2.y = r.y; - newR2.w = r.w - newR.w; - newR2.h = r.h; - boxSplit(newR2, z, end, -1, rl); - return; - } - } - - if (direction == -1) - { - // we are going down the stack - // r is underlapped by boxes[z] - // but we have not split - // Therefore this region under test is - // completely covering boxes[z] - - // don't go any further down, generate a region and quit - -// printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h); - r.z = z; - rl.push_front(r); - } - -// printf("Returning from Z=%i\n", z); - return; - } - else - { -// printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z); - } - } - - // if direction = 1 then we have come to a region that is - // entirely clear of higher boxes and needs to be redrawn - - // if direction = -1 then we have come to a region that is on - // the very bottom with nothing below it to repaint. - // do nothing. stale window data will be left on screen? - - if (direction == 1) - { - rl.push_front(r); - } -} - -void BoxStack::removeAllExceptWallpaper() -{ - // 1.. Don't delete wallpaper. No point. - - // Need locking on this one?? - - // This is pretty silly now that preDelete needs mutex unlocked - - Boxx* toDel = NULL; - VideoDisplay *display = NULL; - - while(numBoxes > 1) - { - boxLock.lock(); - - if (numBoxes == 1) - { - boxLock.unlock(); - break; - } - - toDel = boxes[numBoxes - 1]; - - boxLock.unlock(); - - toDel->preDelete(); - - boxLock.lock(); - - // If boxes[numBoxes - 1] isn't toDel then there's a problem - if (boxes[numBoxes - 1] == toDel) - { - --numBoxes; - } - else - { - LogNT::getInstance()->error(TAG, "Can this actually happen? Why?"); - toDel = NULL; - } - - // FIXME what is this? - if (!videoStack.empty() && videoStack.top().first==toDel) { - videoStack.pop(); - if (!videoStack.empty()) display=&videoStack.top().second; - } - boxLock.unlock(); - - //AVO: do the delete outside the lock to allow for recursive deletes - LogNT::getInstance()->debug(TAG, "removeall: going to delete boxx {}, num={}", static_cast(toDel), numBoxes); - if (display) Video::getInstance()->setVideoDisplay(*display); - - if (toDel) delete toDel; - } -} - -int BoxStack::handleCommand(int command) -{ - int retVal; - int retVal2 = 0; - int i; - - LogNT::getInstance()->debug(TAG, "handle command {}", command); - - if (command != Input::NA_NONE) - { - // handle command return values - // 0 - drop through to next box - // 1 - dont drop to next box, but not handled - // 2 - handled - stop command here - // 4 - handled - delete this box - - for (i=numBoxes-1; i>=0; i--) - { - LogNT::getInstance()->debug(TAG, "Giving command to i={}", i); - retVal = boxes[i]->handleCommand(command); - if (retVal == ABANDON_COMMAND) - { - // not handled but don't give to any more boxes - return 0; - } - - if (retVal == COMMAND_HANDLED) - { - retVal2 = 1; - break; - } - else if (retVal == DELETE_ME) - { -// LogNT::getInstance()->debug(TAG, "Return 4: i={}, boxes[i]={}", i, (void*)boxes[i]); - remove(boxes[i]); - retVal2 = 1; - break; - } - } - } - else - { - // fake the return code - retVal2 = 2; - } - - return retVal2; -} - -void BoxStack::processMessage(Message* m) -{ - if (m->p_to == Message::MOUSE_RECEIVER) - { - // Handle mouse events - // They just need to be delivered to top box - if (numBoxes > 1) boxes[numBoxes-1]->processMessage(m); - return; - } - else if (m->p_to == Message::BOXSTACK) - { - switch(m->message) - { - case Message::CLOSE_ME: - { - remove(static_cast(m->from)); - break; - } - case Message::ADD_VIEW: - { - Boxx* toAdd = reinterpret_cast(m->data); - add(toAdd); - toAdd->draw(); - update(toAdd); - break; - } - } - } -} diff --git a/boxstack.h b/boxstack.h deleted file mode 100644 index fcc36f1..0000000 --- a/boxstack.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef BOXSTACK_H -#define BOXSTACK_H - -#include -#include -#include -#include -#include - -#include "boxx.h" -#include "region.h" -#include "messagequeue.h" -#include "video.h" - -typedef std::list RegionList; -typedef std::stack > VideoDisplayStack; - -class Osd; - -class BoxStack : public MessageReceiver -{ - public: - BoxStack(); - virtual ~BoxStack(); - static BoxStack* getInstance(); - - int init(); - int shutdown(); - - // These functions do internal locking, so can be called directly from any thread. Hopefully. - int add(Boxx*); - int remove(Boxx*); - void removeAllExceptWallpaper(); - void removeAll(); - void update(Boxx*, const Region* regionToUpdate = NULL); - void redrawAllBoxes(); - // -- end - - int handleCommand(int command); - void processMessage(Message* m); - - // handleCommand() return values - const static int DROP_THROUGH = 0; - const static int ABANDON_COMMAND = 1; - const static int COMMAND_HANDLED = 2; - const static int DELETE_ME = 4; - - private: - static BoxStack* instance; - int initted{}; - - Osd* osd{}; - - Boxx* boxes[20]; - int numBoxes{}; - - VideoDisplayStack videoStack; - - std::mutex boxLock; - - void repaintRevealed(int x, Region r); - void boxSplit(Region r, int start, int end, int direction, RegionList& rl); - int addVideoDisplay(Boxx*,VideoDisplay); -}; - -#endif diff --git a/boxx.cc b/boxx.cc deleted file mode 100644 index d5e6342..0000000 --- a/boxx.cc +++ /dev/null @@ -1,644 +0,0 @@ -/* - Copyright 2007-2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#include - -#include "defines.h" -#include "log.h" -#include "message.h" -#include "osd.h" -#include "surface.h" -#include "surfacevector.h" - -#include "boxx.h" - -static const char* TAG = "Boxx"; - -int Boxx::numBoxxes = 0; - -Boxx::Boxx() -{ - vdisplay.mode = None; - - numBoxxes++; - LogNT::getInstance()->debug(TAG, "Construct, now {}", numBoxxes); -} - -Boxx::~Boxx() -{ - if (surface) delete surface; - numBoxxes--; - LogNT::getInstance()->debug(TAG, "Destruct, now {}", numBoxxes); -} - -void Boxx::draw() -{ - if (backgroundColourSet) fillColour(backgroundColour); - - Boxx* currentBoxx; - std::vector::iterator j; - for (j = children.begin(); j != children.end(); j++) - { - currentBoxx = *j; - if (currentBoxx->getVisible()) currentBoxx->draw(); - } -} - -void Boxx::setSize(UINT w, UINT h) -{ - area.w = w; - area.h = h; -} - -void Boxx::setPosition(UINT x, UINT y) -{ - area.x = x; - area.y = y; -} - -void Boxx::createBuffer() -{ - surface = Osd::getInstance()->createNewSurface(); - surface->create(area.w, area.h); -} - -void Boxx::add(Boxx* newChild) -{ - newChild->setParent(this); - children.push_back(newChild); -} - -void Boxx::remove(Boxx* oldChild) -{ - for(std::vector::iterator i = children.begin(); i != children.end(); i++) - { - if (*i == oldChild) - { - children.erase(i); - return; - } - } - LogNT::getInstance()->error(TAG, "Remove child box called, child {} not found", static_cast(oldChild)); -} - -void Boxx::removeVisibleChilds(Region & r) -{ - for(std::vector::iterator i = children.begin(); i != children.end(); i++) - { - if ((*i)->getVisible()) - { - Region temp = (*i)->getRegionR(); - if (r.intersects(temp)) r = r.subtract(temp); - } - } -} - -void Boxx::setParent(Boxx* newParent) -{ - parent = newParent; -} - -void Boxx::setBackgroundColour(const DrawStyle& Tcolour) -{ - backgroundColour = Tcolour; - backgroundColourSet = true; -} - -void Boxx::setVideoBackground() -{ - vdisplay.mode = Window; - vdisplay.fallbackMode = Fullscreen; - vdisplay.x = getScreenX(); - vdisplay.y = getScreenY(); - vdisplay.width = getWidth(); - vdisplay.height = getHeight(); -} - -void Boxx::setVisible(bool isVisible) -{ - visible = isVisible; -} - -bool Boxx::getVisible() const -{ - return visible; -} - -void Boxx::setGap(UINT gap) -{ - paraVSpace = gap; -} - -void Boxx::blt(Region& r) -{ - /* surface update to screen needs: - source x distance into this surface - source y distance into this surface - width of update - height of update - destination x on screen - destination y on screen - */ - - if (parent) abort(); // if (parent) then this is a child boxx. It can not blt. - - // this shouldn't be here - r.x -= area.x; - r.y -= area.y; - - surface->updateToScreen(r.x, r.y, r.w, r.h, area.x + r.x, area.y + r.y); -} - -int Boxx::getScreenX() const -{ - if (parent) return area.x + parent->getScreenX(); - return area.x; -} - -int Boxx::getScreenY() const -{ - if (parent) return area.y + parent->getScreenY(); - return area.y; -} - -int Boxx::getRootBoxOffsetX() const // convert this to be getX and silently do the parent/not thing? same for Y below? -{ - if (parent) return area.x + parent->getRootBoxOffsetX(); - return 0; -} - -int Boxx::getRootBoxOffsetY() const -{ - if (parent) return area.y + parent->getRootBoxOffsetY(); - return 0; -} - -int Boxx::getX() const -{ - return area.x; -} - -int Boxx::getY() const -{ - return area.y; -} - -int Boxx::getX2() const -{ - return area.x + area.w; -} - -int Boxx::getY2() const -{ - return area.y + area.h; -} - -UINT Boxx::getWidth() const -{ - return area.w; -} - -UINT Boxx::getHeight() const -{ - return area.h; -} - -// FIXME Clean up the code to use just one of the following - -const Region* Boxx::getRegion() const -{ - return &area; -} - -Region Boxx::getRegionR() const -{ - return area; -} - -void Boxx::getRootBoxRegion(Region* r) const -{ - // Returns a region that describes the position of this box on the box with the surface - // To be used for boxstack->update calls - - r->x = getRootBoxOffsetX(); - r->y = getRootBoxOffsetY(); - r->w = area.w; - r->h = area.h; -} - -bool Boxx::getVideoDisplay(VideoDisplay &vd) -{ - for(std::vector::iterator i = children.begin(); i != children.end(); i++) - { - if ((*i)->getVideoDisplay(vd)) return true; - } - - if (vdisplay.mode == None) return false; - vd = vdisplay; - return true; -} - -// Level 1 drawing functions - -void Boxx::fillColour(const DrawStyle& colour) -{ - rectangle(0, 0, area.w, area.h, colour); -} - -int Boxx::drawPara(const char* text, int x, int y, const DrawStyle& colour, unsigned int skiplines) -{ - char line[256]; - UINT lineHeight = getFontHeight() + paraVSpace; - float lineWidth; - float thisCharWidth; - int textPos = 0; - int textLength = strlen(text); - int linePos; - UINT ypos = y; - int printLine; - int leftlines = 0; - int drawLinePos = -skiplines; - -#if WIN32 - // FIXME win pragma -#pragma warning(disable : 4146) -#endif - - Region tester; - - bool haschildren = true; - if (children.size() == 0) haschildren = false; - bool mchar = false; - Osd* osd = Osd::getInstance(); - if (osd->charSet() != 1) mchar = true; - OsdVector *osdv = dynamic_cast(osd); - float* charwidtharray = NULL; - if (osdv) charwidtharray = osdv->getCharWidthArray(); - - mbstate_t state; - memset(&state, 0, sizeof(state)); - - while(1) - { - linePos = 0; - lineWidth = 0; - // tester reinit - tester.h = lineHeight; - tester.y = ypos; - tester.x = x; - tester.w = area.w - (2 * paraMargin); - - if (haschildren) removeVisibleChilds(tester); - - while(1) - { - printLine = 0; - int cur_length = 1; - wchar_t cur_char; - if (*(text + textPos) == '\0') break; - if (mchar) - { - cur_length = mbrtowc(&cur_char, text + textPos, textLength-textPos, &state); - if (cur_length <= 0) - { - cur_char = '?'; - cur_length = 1; - } - } - else - { - cur_char = *(text + textPos); - } - - if (cur_char == '\0') break; - - if (cur_char == '\n') - { - textPos += cur_length; // ignore the \n - printLine = 1; - break; - } - - if (charwidtharray) - { - thisCharWidth = charwidtharray[cur_char & 0xFF]; - if (cur_char && 0xFFFFFF00) thisCharWidth = osdv->getCharWidth(cur_char); - } - else - { - thisCharWidth = charWidth(cur_char); - } - - - if ((lineWidth + thisCharWidth + static_cast(x)) > static_cast(tester.w)) - { - // this character would break the right margin - if (cur_char == ' ') - { - // this char is a space, ignore and break - textPos += cur_length; - break; - } - else - { - // Need to go back to the last space in the line - while ((cur_char != ' ') && (linePos >= 0)) - { - textPos -= cur_length; - if (mchar) - { - cur_length = mbrtowc(&cur_char, text + textPos, textLength-textPos, &state); - if (cur_length <= 0) - { - cur_char = '?'; - cur_length = 1; - } - } - else - { - cur_char = *(text + textPos); - } - linePos--; - } - // Now take the space we just found - textPos += cur_length; - break; - } - } - for (int n = 0; n < cur_length; n++) line[linePos++] = text[textPos + n]; - lineWidth += thisCharWidth; - textPos += cur_length; - } - -// line[linePos++] = '\0'; - if (linePos >= 0) line[linePos++] = '\0'; //Here is the change - - if (printLine || (linePos > 1)) // if some text was put in line - { - if (ypos <= (area.h - lineHeight + paraVSpace)) - { - if (drawLinePos >= 0) - { - drawText(line, x, ypos, colour); - ypos += lineHeight; - } - } - else - { - leftlines++; - } - drawLinePos++; - } - else - { - break; - } - } - return leftlines; -} - -void Boxx::rectangle(Region& region, const DrawStyle& colour) -{ - rectangle(region.x, region.y, region.w, region.h, colour); -} - -// Level 0 drawing functions - -void Boxx::rectangle(UINT x, UINT y, UINT w, UINT h, const DrawStyle& colour) -{ - if (parent) parent->rectangle(area.x + x, area.y + y, w, h, colour); - else surface->fillblt(x, y, w, h, colour); -} - -void Boxx::drawText(const char* text, int x, int y, const DrawStyle& colour) -{ - if (parent) parent->drawText(text, area.x + x, area.y + y, colour); - else surface->drawText(text, x, y, colour); -} - -void Boxx::drawText(const char* text, int x, int y, int width, const DrawStyle& colour) -{ - if (parent) parent->drawText(text, area.x + x, area.y + y, width, colour); - else surface->drawText(text, x, y, width, colour); -} - -void Boxx::drawTextRJ(const char* text, int x, int y, const DrawStyle& colour) -{ - if (parent) parent->drawTextRJ(text, area.x + x, area.y + y, colour); - else surface->drawTextRJ(text, x, y, colour); -} - -void Boxx::drawTextCentre(const char* text, int x, int y, const DrawStyle& colour) -{ - if (parent) parent->drawTextCentre(text, area.x + x, area.y + y, colour); - else surface->drawTextCentre(text, x, y, colour); -} - -// std::string versions - the switch back to const char* is currently here - -void Boxx::drawText(const std::string& text, int x, int y, const DrawStyle& colour) -{ - if (parent) parent->drawText(text.c_str(), area.x + x, area.y + y, colour); - else surface->drawText(text.c_str(), x, y, colour); -} - -void Boxx::drawText(const std::string& text, int x, int y, int width, const DrawStyle& colour) -{ - if (parent) parent->drawText(text.c_str(), area.x + x, area.y + y, width, colour); - else surface->drawText(text.c_str(), x, y, width, colour); -} - -void Boxx::drawTextRJ(const std::string& text, int x, int y, const DrawStyle& colour) -{ - if (parent) parent->drawTextRJ(text.c_str(), area.x + x, area.y + y, colour); - else surface->drawTextRJ(text.c_str(), x, y, colour); -} - -void Boxx::drawTextCentre(const std::string& text, int x, int y, const DrawStyle& colour) -{ - if (parent) parent->drawTextCentre(text.c_str(), area.x + x, area.y + y, colour); - else surface->drawTextCentre(text.c_str(), x, y, colour); -} - - -// Now deprecated -/* -void Boxx::drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw) -{ - if (parent) parent->drawPixelAlpha(area.x + x, area.y + y, colour,fastdraw); - else - { - int c = ( (colour.alpha << 24 ) - | (colour.red << 16) - | (colour.green << 8) - | (colour.blue ) ); - - surface->drawPixel(x, y, c,fastdraw); - } -} - -void Boxx::drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw) -{ - if (parent) parent->drawPixel(area.x + x, area.y + y, colour,fastdraw); - else - { - int c = ( (0xFF000000 ) - | (colour.red << 16) - | (colour.green << 8) - | (colour.blue ) ); - - surface->drawPixel(x, y, c,fastdraw); - } -} -*/ - -void Boxx::drawTTChar(int ox, int oy, int x, int y, cTeletextChar c) -{ - if (parent) parent->drawTTChar(area.x + ox, area.y + oy, x,y,c); - else if (surface) surface->drawTTChar(ox, oy,x,y,c); -} - -void Boxx::drawBitmap(UINT x, UINT y, const Bitmap& bm, const DisplayRegion & region) -{ - if (parent) parent->drawBitmap(area.x + x, area.y + y, bm, region); - else if (surface) surface->drawBitmap(x, y, bm, region); -} - -void Boxx::drawJpeg(const char* fileName, int x, int y, int *width, int *height) -{ - if (parent) parent->drawJpeg(fileName, area.x + x, area.y + y, width, height); - else if (surface) surface->drawJpeg(fileName, x, y, width, height); -} - -void Boxx::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsigned int width, const DrawStyle& nextColour) -{ - if (parent) parent->drawMonoBitmap(base, area.x +dx, area.y + dy, height, width, nextColour); - else if (surface) surface->drawMonoBitmap(base, dx,dy, height, width, nextColour); -} - -void Boxx::drawImage(Image& image, float x, float y, float width, float height, Corner corner) -{ - if (parent) parent->drawImage(image, static_cast(area.x) + x, static_cast(area.y) + y, width, height, corner); - else if (surface) - { - SurfaceVector* surfacevector = dynamic_cast(surface); - if (surfacevector) surfacevector->drawImage(image, x, y, width, height, corner); - else surface->fillblt(static_cast(x), static_cast(y), static_cast(width), static_cast(height), DrawStyle::RED); // Signal that something went wrong - } -} - -void Boxx::drawClippingRectangle(float x, float y, float w, float h) -{ - if (parent) parent->drawClippingRectangle(static_cast(area.x) + x, static_cast(area.y) + y, w, h); - else if (surface) - { - SurfaceVector* surfacevector = dynamic_cast(surface); - if (surfacevector) surfacevector->drawClippingRectangle(x, y, w, h); - } -} - -int Boxx::getFontHeight() -{ - if (parent) return parent->getFontHeight(); - else if (surface) return surface->getFontHeight(); - else return 18; -} - -void Boxx::startFastDraw() -{ - if (parent) - { - parent->startFastDraw(); - } - else - { - if (surface) surface->startFastDraw(); - } -} - -void Boxx::endFastDraw() -{ - if (parent) - { - parent->endFastDraw(); - } - else - { - if (surface) surface->endFastDraw(); - } -} - -float Boxx::charWidth(wchar_t c) -{ - if (parent) return parent->charWidth(c); - else if (surface) return surface->getCharWidth(c); - else return 16.; //? -} - -Surface* Boxx::getSurface() -{ - if (parent) return parent->getSurface(); - return surface; -} - -bool Boxx::mouseMove(int x, int y) -{ - if ( (x >= static_cast(area.x)) && (x < static_cast(area.x2())) - && (y >= static_cast(area.y)) && (y < static_cast(area.y2())) ) - { - return true; - } - else - { - return false; - } -} - -bool Boxx::mouseLBDOWN(int x, int y) -{ - if ( (x >= static_cast(area.x)) && (x < static_cast(area.x2())) - && (y >= static_cast(area.y)) && (y < static_cast(area.y2())) ) - { - return true; - } - else - { - return false; - } -} - -bool Boxx::coordsOutsideBox(Message* m) -{ - /* Helper function to look at x and y in m - * and see if the point is outside this Boxx's area - */ - - int x = m->parameter - getScreenX(); - int y = m->tag - getScreenY(); - - if ( (x < 0) - || (y < 0) - || (x > static_cast(area.w)) - || (y > static_cast(area.h)) - ) - return true; - - return false; -} - diff --git a/boxx.h b/boxx.h deleted file mode 100644 index 6f8f521..0000000 --- a/boxx.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef BOXX_H -#define BOXX_H - -#include - -#include "bitmap.h" -#include "colour.h" -#include "region.h" -#include "video.h" -#include "image.h" -#include "teletextdecodervbiebu.h" - -#include "osdvectortypes.h" // FIXME Only included for enum Corner. Fix this one day. - -class Bitmap; -class Message; -class Surface; - -class Boxx -{ - public: - Boxx(); - virtual ~Boxx(); - - virtual void setSize(UINT w, UINT h); // virtual? really? - void setPosition(UINT x, UINT y); // Set position on parent. Even numbers only!!! - void createBuffer(); // Make this a root view that goes in the BoxStack - virtual void draw(); - - void setGap(UINT gap); - void setBackgroundColour(const DrawStyle& colour); - void setVisible(bool isVisible); - void setVideoBackground(); - - // The following are supposed to be abstract functions - // However, it is useful to be able to make instances of Boxx - // Therefore the following stubs are provided. - virtual void preDelete() {} - virtual int handleCommand(int) { return 0; } - virtual void processMessage(Message*) {} - virtual bool mouseMove(int x, int y); - virtual bool mouseLBDOWN(int x, int y); - virtual bool mouseAndroidScroll(int /* x */, int /* y */, int /* sx */, int /* sy */) { return false; } - virtual void deactivateAllControls() {} - - /* preDelete - - I think it's functionally equivalent to e.g. delete timers in Boxx::preDelete - because the only place where a Boxx is deleted is in - BoxStack::remove. There is now a call in BoxStack::remove to Boxx::preDelete - The reason for this is to stop timercalls calling BoxStack::update at the - same time BoxStack::remove is locked trying to delete the Boxx - */ - - // Get functions - int getScreenX() const; // where is it on screen - int getScreenY() const; - int getRootBoxOffsetX() const; // where is it relative to the top-parent in the boxstack - int getRootBoxOffsetY() const; - int getX() const; // where is it relative to its parent - int getX2() const; // .. and the right edge - int getY() const; - int getY2() const; - UINT getWidth() const; - UINT getHeight() const; - bool getVisible() const; - const Region* getRegion() const; - Region getRegionR() const; // Same but as an object - void getRootBoxRegion(Region*) const; - - bool getVideoDisplay(VideoDisplay &vd); - - bool coordsOutsideBox(Message*); - - // Drawing functions level 1 - void fillColour(const DrawStyle & colour); - int drawPara(const char* text, int x, int y, const DrawStyle& colour, unsigned int skiplines=0); - - // Drawing functions level 0 - void rectangle(UINT x, UINT y, UINT w, UINT h, const DrawStyle& colour); - void rectangle(Region& region, const DrawStyle& colour); - - void drawText(const char* text, int x, int y, const DrawStyle& colour); - void drawText(const char* text, int x, int y, int width, const DrawStyle& colour); - void drawTextRJ(const char* text, int x, int y, const DrawStyle& colour); - void drawTextCentre(const char* text, int x, int y, const DrawStyle& colour); - // std::string versions - void drawText(const std::string& text, int x, int y, const DrawStyle& colour); - void drawText(const std::string& text, int x, int y, int width, const DrawStyle& colour); - void drawTextRJ(const std::string& text, int x, int y, const DrawStyle& colour); - void drawTextCentre(const std::string& text, int x, int y, const DrawStyle& colour); - //Now deprecated - //void drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw=false); - void drawBitmap(UINT x, UINT y, const Bitmap& bm, const DisplayRegion& region); - //Now deprecated - // void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false); - void drawImage(Image& image, float x, float y, float width, float height, Corner corner=TopLeft); - void drawClippingRectangle(float x, float y, float w, float h); - int getFontHeight(); - - void drawJpeg(const char *fileName,int x, int y,int *width, int *height); - - void drawTTChar(int ox, int oy,int x, int y, cTeletextChar c); - void drawMonoBitmap(UCHAR*base, int dx, int dy, unsigned int height,unsigned int width, const DrawStyle& nextColour); - - /* This is for system which need a locking of the drawing surface to speed up drawing */ - void startFastDraw(); - void endFastDraw(); - - float charWidth(wchar_t c); - - void add(Boxx*); // a boxx has a set of child boxxs - void remove(Boxx*); - - /* - The following function sets the child's parent pointer without adding the child to the children vector. - It's a hack (that should be deprecated?) to allow things like WSymbol to be created, do some drawing on - the surface and then be deleted again, leaving the drawing present. - A better design would be to create many WSymbols - one per symbol and leave them created - then the - automatic draw code will be able to redraw the symbols without all that code needing - to be in the derived boxx's draw method. - */ - void TEMPADD(Boxx* child) { child->setParent(this); } - - friend class BoxStack; - protected: - //get the surface this box is drawing to - Surface* getSurface(); - - // I want a parent box or a surface. - Boxx* parent{}; - Surface* surface{}; - - Region area; - std::vector children; - VideoDisplay vdisplay; - - void setParent(Boxx*); - void blt(Region& r); - void removeVisibleChilds(Region & r); - - static const int paraMargin = 10; - UINT paraVSpace{6}; // default gap for drawPara - - DrawStyle backgroundColour; - bool backgroundColourSet{}; - bool visible{true}; - - static int numBoxxes; -}; - -#endif - - -/* - -New Boxx design - -It's "Boxx" because "Box" was already taken. - -BoxStack replaces Viewman and handles displaying a stack of root boxxs (boxxs with surfaces) on the screen. - -Boxx relaces Box, Widget and parts of View and represents a box with or without a surface. -Let's call a Boxx with a surface a root box, and a boxx without a surface a child box. - -A boxx with a surface (root) is like an old View and is handled by BoxStack. -A boxx without a surface (child) is like and old Widget and needs to be a child box of another boxx (root or not). - -Don't add a boxx with a surface to another boxx. That isn't the design. - -So, when you create a boxx, either that boxx calls createBuffer() on itself, -or some other box add()s the new box to itself. - -Root boxxs can overlap each other - this is managed by boxstack. -Child boxxs within a parent boxx do not overlap each other. -However, a grandchild box can overlap a child box (but must be entirely contained within the child box). - -TBBoxx replaces View but is now only a convenience class for the window dressing stuff. It isn't required anymore since -all the real work that view used to do is done in Boxx now. - -Obseleted classes: Box, View, Viewman, Widget, others? -No code outside boxx should talk about surfaces anymore. Hopefully. - -*/ diff --git a/buffer.cc b/buffer.cc deleted file mode 100644 index dbb33f7..0000000 --- a/buffer.cc +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright 2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#include - -#include "buffer.h" - -Buffer::~Buffer() -{ - if (memory) free(memory); -} - -void Buffer::set(void* newptr) -{ - if (memory) abort(); - memory = newptr; -} - -void Buffer::release() -{ - if (memory) free(memory); - memory = nullptr; -} - -unsigned char* Buffer::ucharp() -{ - return reinterpret_cast(memory); -} diff --git a/buffer.h b/buffer.h deleted file mode 100644 index e5aee0b..0000000 --- a/buffer.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright 2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef BUFFER_H -#define BUFFER_H - -class Buffer -{ - public: - Buffer() {}; - Buffer(const Buffer&) = delete; // copy - Buffer& operator=(const Buffer&) = delete; // assign - Buffer(Buffer&&) = delete; // move - Buffer& operator=(Buffer&&) = delete; // move-assign - - ~Buffer(); - - void set(void* mem); - bool isNull() { return (memory == nullptr); } - void release(); - - unsigned char* ucharp(); - - private: - void* memory{}; -}; - -#endif diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..eb8b731 --- /dev/null +++ b/build.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +NATIVE=NO + +if grep -q BCM2708 /proc/cpuinfo ; then + NATIVE=yes +elif grep -q BCM2709 /proc/cpuinfo ; then + NATIVE=yes +elif grep -q BCM2835 /proc/cpuinfo ; then + NATIVE=yes +else + NATIVE=no +fi + +if [ $NATIVE == "no" ]; then + CROSS_COMPILE_INSERT=-DCMAKE_TOOLCHAIN_FILE=../src/CMakeToolChainRPi.txt +fi + +mkdir build +cmake $CROSS_COMPILE_INSERT -S src -B build && make -C build -j8 diff --git a/callback.h b/callback.h deleted file mode 100644 index 9acd39d..0000000 --- a/callback.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef CALLBACK_H -#define CALLBACK_H - -class Callback -{ - public: - virtual ~Callback() {} - virtual void call(void* caller)=0; -}; - -#endif diff --git a/channel.cc b/channel.cc deleted file mode 100644 index 8e6f22f..0000000 --- a/channel.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#include "channel.h" - -#include "vdr.h" -#include "log.h" -#include "control.h" - -static const char* TAG = "Channel"; - -void Channel::loadPids() -{ - // Clear the list if this is a reload - if (numAPids) - { - apids.clear(); - dpids.clear(); - spids.clear(); - vpid = 0; - tpid = 0; - numAPids = 0; - numDPids = 0; - numSPids = 0; - } - - VDR::getInstance()->getChannelPids(this); // FIXME sort out this system - if (!VDR::getInstance()->isConnected()) - { - Control::getInstance()->connectionLost(); - return; - } - - LogNT* logger = LogNT::getInstance(); - - - logger->debug(TAG, "C.{} loaded, VPid={}, numApids={}, numDpids={}, numSpids={} TPid={}", - number, vpid, numAPids, numDPids, numSPids, tpid); - for (ULONG i = 0; i < numAPids; i++) - { - logger->debug(TAG, "APid {} {} {}", apids[i].pid, apids[i].desc,apids[i].type); - } - for (ULONG i = 0; i < numDPids; i++) - { - logger->debug(TAG, "DPid {} {} {}", dpids[i].pid, dpids[i].desc,dpids[i].type); - } - for (ULONG i = 0; i < numSPids; i++) - { - logger->debug(TAG, "SPid {} {} {} {} {}", spids[i].pid, spids[i].desc,spids[i].type,spids[i].data1,spids[i].data2); - } -} diff --git a/channel.h b/channel.h deleted file mode 100644 index 1825400..0000000 --- a/channel.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef CHANNEL_H -#define CHANNEL_H - -#include -#include - -#include "defines.h" - -// A struct to hold a audio pid pair - -typedef struct _apid -{ - ULONG pid; - char desc[10]; - ULONG type; - ULONG data1; - ULONG data2; -} apid; - -typedef std::vector APidList; - -class Channel -{ - public: - void loadPids(); - - int index{-1}; - ULONG number{}; - ULONG type{}; - UCHAR vstreamtype{2}; //Mpeg2 - std::string name; - - ULONG vpid{}; - ULONG numAPids{}; - APidList apids; - ULONG numDPids{}; - APidList dpids; - ULONG numSPids{}; - APidList spids; - ULONG tpid{}; -}; - -#endif diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..bc9bfaa --- /dev/null +++ b/clean.sh @@ -0,0 +1,2 @@ +#!/bin/bash +rm -rf build diff --git a/colour.cc b/colour.cc deleted file mode 100644 index cf75ca8..0000000 --- a/colour.cc +++ /dev/null @@ -1,454 +0,0 @@ -/* - Copyright 2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#include "colour.h" -#include "defines.h" - -DrawStyle DrawStyle::TRANSPARENT(0, 0, 0, 0); -DrawStyle DrawStyle::WHITE(255, 255, 255); -DrawStyle DrawStyle::BLACK(0, 0, 0); -DrawStyle DrawStyle::RED(255, 0, 0); -DrawStyle DrawStyle::GREEN(0, 255, 0); -DrawStyle DrawStyle::GREY(180, 180, 180); -DrawStyle DrawStyle::DARKGREY(100, 100, 100); -DrawStyle DrawStyle::BLUE(0, 0, 255); -DrawStyle DrawStyle::YELLOW(255, 255, 0); -DrawStyle DrawStyle::VIDEOBLUE(0, 0, 150); -DrawStyle DrawStyle::VIEWBACKGROUND(0, 0, 100); -DrawStyle DrawStyle::VIEWTRANSPARENTBACKGROUND(0, 0, 100, 128); -DrawStyle DrawStyle::TABVIEWBACKGROUND(0, 0, 120); -DrawStyle DrawStyle::TITLEBARBACKGROUND(0, 0, 200); -DrawStyle DrawStyle::SELECTHIGHLIGHT(240, 250, 80); -DrawStyle DrawStyle::LIVETVSYMBOLS(240, 250, 80); -DrawStyle DrawStyle::SELECTDARKHIGHLIGHT(120, 125, 40); -DrawStyle DrawStyle::SELECTBACKGROUND(0, 0, 100); -DrawStyle DrawStyle::PROGRESSBAR(255, 255, 255); -DrawStyle DrawStyle::LIGHTTEXT(255, 255, 255); -DrawStyle DrawStyle::DARKTEXT(0, 0, 100); -DrawStyle DrawStyle::DANGER(200, 0, 0); -DrawStyle DrawStyle::OSDBACKGROUND(0, 0, 0, 128); -DrawStyle DrawStyle::BUTTONBACKGROUND(0, 0, 200); -DrawStyle DrawStyle::PROGRAMMEB(80, 80, 240); // two colours used as alterating backgrounds for individual programmes in EPG -DrawStyle DrawStyle::PROGRAMMEA(40, 40, 120); // TODO fit epg style (colours) in with rest of application -DrawStyle DrawStyle::NOPROGRAMME(180, 180, 180); // no programme details colour -DrawStyle DrawStyle::WALLPAPER(0xFF000000); - - -const char* skinnames[] = -{ -#ifdef GRADIENT_DRAWING - "Noopacity inspired", - "VompClassic Enhanced", -#endif - "VompClassic" -}; - -const char ** SkinFactory::getSkinNames() -{ - return skinnames; -} - -int SkinFactory::getNumberofSkins() -{ - return MaxSkins; -} - -void SkinFactory::InitDefaultSkin() -{ - /* - Real colours - */ - DrawStyle::BLACK = DrawStyle(0, 0, 0); - DrawStyle::RED = DrawStyle(255, 0, 0); - DrawStyle::GREY = DrawStyle(180, 180, 180); - DrawStyle::DARKGREY = DrawStyle(100, 100, 100); - DrawStyle::GREEN = DrawStyle(0, 255, 0); - DrawStyle::BLUE = DrawStyle(0, 0, 255); - DrawStyle::YELLOW = DrawStyle(255, 255, 0); - DrawStyle::WALLPAPER = DrawStyle(0, 0, 150); - DrawStyle::VIEWBACKGROUND = DrawStyle(0, 0, 100); - DrawStyle::SELECTBACKGROUND = DrawStyle(0, 0, 100); - DrawStyle::VIEWTRANSPARENTBACKGROUND = DrawStyle(0, 0, 100, 128); - DrawStyle::TABVIEWBACKGROUND = DrawStyle(0, 0, 120); - DrawStyle::TITLEBARBACKGROUND = DrawStyle(0, 0, 200); - DrawStyle::LIVETVSYMBOLS = DrawStyle(240, 250, 80); - DrawStyle::SELECTHIGHLIGHT = DrawStyle(240, 250, 80); - DrawStyle::SELECTDARKHIGHLIGHT = DrawStyle(120, 125, 40); - DrawStyle::PROGRESSBAR = DrawStyle::LIGHTTEXT = DrawStyle(255, 255, 255); - DrawStyle::DARKTEXT = DrawStyle(0, 0, 100); - DrawStyle::DANGER = DrawStyle(200, 0, 0); - DrawStyle::BUTTONBACKGROUND = DrawStyle(0, 0, 200); - DrawStyle::OSDBACKGROUND = DrawStyle(0, 0, 0, 128); - DrawStyle::PROGRAMMEB = DrawStyle(80, 80, 240); // two colours used as alterating backgrounds for individual programmes in EPG - DrawStyle::PROGRAMMEA = DrawStyle(40, 40, 120); // TODO fit epg style (colours) in with rest of application - DrawStyle::NOPROGRAMME = DrawStyle(180, 180, 180); // no programme details colour - - /* - Silly colours - - Colour Colour::VIDEOBLUE(250, 0, 0); - Colour Colour::VIEWBACKGROUND(100, 0, 100); - Colour Colour::TITLEBARBACKGROUND(100, 0, 200); - Colour Colour::SELECTHIGHLIGHT(240, 250, 180); - Colour Colour::LIGHTTEXT(255, 0, 255); - Colour Colour::DARKTEXT(0, 0, 255); - Colour Colour::DANGER(200, 200, 0); - Colour Colour::BUTTONBACKGROUND(255, 255, 255); - */ -} - -void SkinFactory::InitEnhancedSkin() -{ - /* - Real colours - */ - DrawStyle::BLACK = DrawStyle(0, 0, 0); - - DrawStyle::RED = DrawStyle(100, 0, 0); - DrawStyle::RED.grad_col[0] = Colour(255, 0, 0); - DrawStyle::RED.grad_col[1] = Colour(100, 0, 0); - DrawStyle::RED.grad_pos[0] = 0.5; - DrawStyle::RED.num_colors = 2; - DrawStyle::RED.ft = DrawStyle::GradientLinear; - DrawStyle::RED.x1 = 0.0; - DrawStyle::RED.y1 = 0.0; - DrawStyle::RED.x2 = 0.0; - DrawStyle::RED.y2 = 1.0; - - DrawStyle::GREEN = DrawStyle(0, 100, 0); - DrawStyle::GREEN.grad_col[0] = Colour(0, 255, 0); - DrawStyle::GREEN.grad_col[1] = Colour(0, 100, 0); - DrawStyle::GREEN.grad_pos[0] = 0.5; - DrawStyle::GREEN.num_colors = 2; - DrawStyle::GREEN.ft = DrawStyle::GradientLinear; - DrawStyle::GREEN.x1 = 0.0; - DrawStyle::GREEN.y1 = 0.0; - DrawStyle::GREEN.x2 = 0.0; - DrawStyle::GREEN.y2 = 1.0; - - DrawStyle::BLUE = DrawStyle(0, 0, 100); - DrawStyle::BLUE.grad_col[0] = Colour(0, 0, 255); - DrawStyle::BLUE.grad_col[1] = Colour(0, 0, 100); - DrawStyle::BLUE.grad_pos[0] = 0.5; - DrawStyle::BLUE.num_colors = 2; - DrawStyle::BLUE.ft = DrawStyle::GradientLinear; - DrawStyle::BLUE.x1 = 0.0; - DrawStyle::BLUE.y1 = 0.0; - DrawStyle::BLUE.x2 = 0.0; - DrawStyle::BLUE.y2 = 1.0; - - DrawStyle::YELLOW = DrawStyle(100, 100, 0); - DrawStyle::YELLOW.grad_col[0] = Colour(255, 255, 0); - DrawStyle::YELLOW.grad_col[1] = Colour(100, 100, 0); - DrawStyle::YELLOW.grad_pos[0] = 0.5; - DrawStyle::YELLOW.num_colors = 2; - DrawStyle::YELLOW.ft = DrawStyle::GradientLinear; - DrawStyle::YELLOW.x1 = 0.0; - DrawStyle::YELLOW.y1 = 0.0; - DrawStyle::YELLOW.x2 = 0.0; - DrawStyle::YELLOW.y2 = 1.0; - - DrawStyle::GREY = DrawStyle(100, 100, 100); - DrawStyle::GREY.grad_col[0] = Colour(180, 180, 180); - DrawStyle::GREY.grad_col[1] = Colour(100, 100, 100); - DrawStyle::GREY.grad_pos[0] = 0.5; - DrawStyle::GREY.num_colors = 2; - DrawStyle::GREY.ft = DrawStyle::GradientLinear; - DrawStyle::GREY.x1 = 0.0; - DrawStyle::GREY.y1 = 0.0; - DrawStyle::GREY.x2 = 0.0; - DrawStyle::GREY.y2 = 1.0; - - DrawStyle::DARKGREY = DrawStyle(50, 50, 50); - DrawStyle::DARKGREY.grad_col[0] = Colour(100, 100, 100); - DrawStyle::DARKGREY.grad_col[1] = Colour(80, 80, 80); - DrawStyle::DARKGREY.grad_pos[0] = 0.5; - DrawStyle::DARKGREY.num_colors = 2; - DrawStyle::DARKGREY.ft = DrawStyle::GradientLinear; - DrawStyle::DARKGREY.x1 = 0.0; - DrawStyle::DARKGREY.y1 = 0.0; - DrawStyle::DARKGREY.x2 = 0.0; - DrawStyle::DARKGREY.y2 = 1.0; - - - DrawStyle::WALLPAPER = DrawStyle(0, 0, 150); - - DrawStyle::VIEWBACKGROUND = DrawStyle(0, 0, 100); - DrawStyle::VIEWBACKGROUND.grad_col[0] = Colour(0, 0, 160); - DrawStyle::VIEWBACKGROUND.num_colors = 1; - DrawStyle::VIEWBACKGROUND.ft = DrawStyle::GradientLinear; - DrawStyle::VIEWBACKGROUND.x1 = 0.0; - DrawStyle::VIEWBACKGROUND.y1 = 0.0; - DrawStyle::VIEWBACKGROUND.x2 = 0.0; - DrawStyle::VIEWBACKGROUND.y2 = 1.0; - - DrawStyle::VIEWTRANSPARENTBACKGROUND = DrawStyle(0, 0, 100, 128); - DrawStyle::VIEWTRANSPARENTBACKGROUND.grad_col[0] = Colour(0, 0, 160, 128); - DrawStyle::VIEWTRANSPARENTBACKGROUND.num_colors = 1; - DrawStyle::VIEWTRANSPARENTBACKGROUND.ft = DrawStyle::GradientLinear; - DrawStyle::VIEWTRANSPARENTBACKGROUND.x1 = 0.0; - DrawStyle::VIEWTRANSPARENTBACKGROUND.y1 = 0.0; - DrawStyle::VIEWTRANSPARENTBACKGROUND.x2 = 0.0; - DrawStyle::VIEWTRANSPARENTBACKGROUND.y2 = 1.0; - - DrawStyle::TABVIEWBACKGROUND = DrawStyle(0, 0, 120); - - - DrawStyle::TITLEBARBACKGROUND = DrawStyle(0, 0, 160); - DrawStyle::TITLEBARBACKGROUND.grad_col[0] = Colour(0, 0, 250); - DrawStyle::TITLEBARBACKGROUND.num_colors = 1; - DrawStyle::TITLEBARBACKGROUND.ft = DrawStyle::GradientLinear; - DrawStyle::TITLEBARBACKGROUND.x1 = 0.0; - DrawStyle::TITLEBARBACKGROUND.y1 = 0.0; - DrawStyle::TITLEBARBACKGROUND.x2 = 0.0; - DrawStyle::TITLEBARBACKGROUND.y2 = 1.0; - - - DrawStyle::SELECTHIGHLIGHT = DrawStyle(120, 125, 40); - DrawStyle::SELECTHIGHLIGHT.grad_col[0] = DrawStyle(240, 250, 80); - DrawStyle::SELECTHIGHLIGHT.num_colors = 1; - DrawStyle::SELECTHIGHLIGHT.ft = DrawStyle::GradientLinear; - DrawStyle::SELECTHIGHLIGHT.x1 = 0.0; - DrawStyle::SELECTHIGHLIGHT.y1 = 0.0; - DrawStyle::SELECTHIGHLIGHT.x2 = 0.0; - DrawStyle::SELECTHIGHLIGHT.y2 = 1.0; - - DrawStyle::LIVETVSYMBOLS = DrawStyle::SELECTHIGHLIGHT; - - - DrawStyle::SELECTDARKHIGHLIGHT = DrawStyle(60, 65, 20); - DrawStyle::SELECTDARKHIGHLIGHT.grad_col[0] = DrawStyle(120, 125, 40); - DrawStyle::SELECTDARKHIGHLIGHT.num_colors = 1; - DrawStyle::SELECTDARKHIGHLIGHT.ft = DrawStyle::GradientLinear; - DrawStyle::SELECTDARKHIGHLIGHT.x1 = 0.0; - DrawStyle::SELECTDARKHIGHLIGHT.y1 = 0.0; - DrawStyle::SELECTDARKHIGHLIGHT.x2 = 0.0; - DrawStyle::SELECTDARKHIGHLIGHT.y2 = 1.0; - - DrawStyle::SELECTBACKGROUND = DrawStyle(0, 0, 100); - DrawStyle::SELECTBACKGROUND.grad_col[0] = Colour(0, 0, 160); - DrawStyle::SELECTBACKGROUND.num_colors = 1; - DrawStyle::SELECTBACKGROUND.ft = DrawStyle::GradientLinear; - DrawStyle::SELECTBACKGROUND.x1 = 0.0; - DrawStyle::SELECTBACKGROUND.y1 = 0.0; - DrawStyle::SELECTBACKGROUND.x2 = 0.0; - DrawStyle::SELECTBACKGROUND.y2 = 1.0; - - DrawStyle::LIGHTTEXT = DrawStyle(255, 255, 255); - DrawStyle::LIGHTTEXT.grad_col[0] = DrawStyle(150, 150, 150); - DrawStyle::LIGHTTEXT.num_colors = 1; - DrawStyle::LIGHTTEXT.ft = DrawStyle::GradientLinear; - DrawStyle::LIGHTTEXT.x1 = 0.0; - DrawStyle::LIGHTTEXT.y1 = 0.0; - DrawStyle::LIGHTTEXT.x2 = 0.0; - DrawStyle::LIGHTTEXT.y2 = 1.0; - DrawStyle::PROGRESSBAR = DrawStyle::LIGHTTEXT; - - DrawStyle::DARKTEXT = DrawStyle(0, 0, 100); - DrawStyle::DANGER = DrawStyle(200, 0, 0); - - DrawStyle::BUTTONBACKGROUND = DrawStyle(0, 0, 100); - DrawStyle::BUTTONBACKGROUND.grad_col[0] = DrawStyle(0, 0, 200); - DrawStyle::BUTTONBACKGROUND.num_colors = 1; - DrawStyle::BUTTONBACKGROUND.ft = DrawStyle::GradientLinear; - DrawStyle::BUTTONBACKGROUND.x1 = 0.0; - DrawStyle::BUTTONBACKGROUND.y1 = 0.0; - DrawStyle::BUTTONBACKGROUND.x2 = 0.0; - DrawStyle::BUTTONBACKGROUND.y2 = 1.0; - - DrawStyle::OSDBACKGROUND = DrawStyle(0, 0, 0, 128); - - - DrawStyle::PROGRAMMEB = DrawStyle(40, 40, 120); // two colours used as alterating backgrounds for individual programmes in EPG - DrawStyle::PROGRAMMEB.grad_col[0] = DrawStyle(80, 80, 240); - DrawStyle::PROGRAMMEB.num_colors = 1; - DrawStyle::PROGRAMMEB.ft = DrawStyle::GradientLinear; - DrawStyle::PROGRAMMEB.x1 = 0.0; - DrawStyle::PROGRAMMEB.y1 = 0.0; - DrawStyle::PROGRAMMEB.x2 = 0.0; - DrawStyle::PROGRAMMEB.y2 = 1.0; - - - DrawStyle::PROGRAMMEA = DrawStyle(80, 80, 240); // TODO fit epg style (colours) in with rest of application - DrawStyle::PROGRAMMEA.grad_col[0] = DrawStyle(40, 40, 120); - DrawStyle::PROGRAMMEA.num_colors = 1; - DrawStyle::PROGRAMMEA.ft = DrawStyle::GradientLinear; - DrawStyle::PROGRAMMEA.x1 = 0.0; - DrawStyle::PROGRAMMEA.y1 = 0.0; - DrawStyle::PROGRAMMEA.x2 = 0.0; - DrawStyle::PROGRAMMEA.y2 = 1.0; - - - DrawStyle::NOPROGRAMME = DrawStyle(180, 180, 180); // no programme details colour - DrawStyle::NOPROGRAMME.grad_col[0] = DrawStyle(90, 90, 90); - DrawStyle::NOPROGRAMME.num_colors = 1; - DrawStyle::NOPROGRAMME.ft = DrawStyle::GradientLinear; - DrawStyle::NOPROGRAMME.x1 = 0.0; - DrawStyle::NOPROGRAMME.y1 = 0.0; - DrawStyle::NOPROGRAMME.x2 = 0.0; - DrawStyle::NOPROGRAMME.y2 = 1.0; - - - /* - Silly colours - - Colour Colour::VIDEOBLUE(250, 0, 0); - Colour Colour::VIEWBACKGROUND(100, 0, 100); - Colour Colour::TITLEBARBACKGROUND(100, 0, 200); - Colour Colour::SELECTHIGHLIGHT(240, 250, 180); - Colour Colour::LIGHTTEXT(255, 0, 255); - Colour Colour::DARKTEXT(0, 0, 255); - Colour Colour::DANGER(200, 200, 0); - Colour Colour::BUTTONBACKGROUND(255, 255, 255); - */ -} - -void SkinFactory::InitNoopacityInspiredSkin() -{ - /* - Real colours - */ - DrawStyle::BLACK = DrawStyle(0, 0, 0); - DrawStyle::RED = DrawStyle(0x99BB0000); - DrawStyle::GREY = DrawStyle(0xFE777777); - DrawStyle::DARKGREY = DrawStyle(0x7D000000); - DrawStyle::GREEN = DrawStyle(0x9900BB00); - DrawStyle::BLUE = DrawStyle(0x990000BB); - DrawStyle::YELLOW = DrawStyle(0x99BBBB00); - DrawStyle::VIEWBACKGROUND = DrawStyle(0xB012273f); - DrawStyle::VIEWTRANSPARENTBACKGROUND = DrawStyle(0x99242A38); - DrawStyle::OSDBACKGROUND = DrawStyle(0xB012273f); - DrawStyle::TABVIEWBACKGROUND = DrawStyle(0x99242A38); - - DrawStyle::LIVETVSYMBOLS = DrawStyle(0xFF9a9a9a); - DrawStyle::PROGRESSBAR = DrawStyle(0xFFC6D590); - - - - DrawStyle::SELECTHIGHLIGHT = DrawStyle(0xFF999999); - DrawStyle::SELECTHIGHLIGHT.grad_col[0] = DrawStyle(0xFFa4fd15); - DrawStyle::SELECTHIGHLIGHT.grad_col[1] = DrawStyle(0xFFa4fd15); - DrawStyle::SELECTHIGHLIGHT.grad_col[2] = DrawStyle(0x7D000000); - DrawStyle::SELECTHIGHLIGHT.grad_pos[0] = 0.3f; - DrawStyle::SELECTHIGHLIGHT.grad_pos[1] = 0.9f; - DrawStyle::SELECTHIGHLIGHT.num_colors = 3; - DrawStyle::SELECTHIGHLIGHT.ft = DrawStyle::GradientLinear; - DrawStyle::SELECTHIGHLIGHT.x1 = 0.0f; - DrawStyle::SELECTHIGHLIGHT.y1 = 0.2f; - DrawStyle::SELECTHIGHLIGHT.x2 = 1.1f; - DrawStyle::SELECTHIGHLIGHT.y2 = 0.8f; - - - DrawStyle::SELECTDARKHIGHLIGHT = DrawStyle(0xFD999999); - DrawStyle::SELECTDARKHIGHLIGHT.grad_col[0] = DrawStyle(0xFF7bbd0f); - DrawStyle::SELECTDARKHIGHLIGHT.grad_col[1] = DrawStyle(0xFF7bbd0f); - DrawStyle::SELECTDARKHIGHLIGHT.grad_col[2] = DrawStyle(0x7D000000); - DrawStyle::SELECTDARKHIGHLIGHT.grad_pos[0] = 0.3f; - DrawStyle::SELECTDARKHIGHLIGHT.grad_pos[1] = 0.9f; - DrawStyle::SELECTDARKHIGHLIGHT.num_colors = 3; - DrawStyle::SELECTDARKHIGHLIGHT.ft = DrawStyle::GradientLinear; - DrawStyle::SELECTDARKHIGHLIGHT.x1 = 0.0f; - DrawStyle::SELECTDARKHIGHLIGHT.y1 = 0.2f; - DrawStyle::SELECTDARKHIGHLIGHT.x2 = 1.1f; - DrawStyle::SELECTDARKHIGHLIGHT.y2 = 0.8f; - - - DrawStyle::SELECTBACKGROUND = DrawStyle(0xFE999999); - DrawStyle::SELECTBACKGROUND.grad_col[0] = DrawStyle(0xFF353b50); - DrawStyle::SELECTBACKGROUND.grad_col[1] = DrawStyle(0xFF353b50); - DrawStyle::SELECTBACKGROUND.grad_col[2] = DrawStyle(0x7D000000); - DrawStyle::SELECTBACKGROUND.grad_pos[0] = 0.3f; - DrawStyle::SELECTBACKGROUND.grad_pos[1] = 0.9f; - DrawStyle::SELECTBACKGROUND.num_colors = 3; - DrawStyle::SELECTBACKGROUND.ft = DrawStyle::GradientLinear; - DrawStyle::SELECTBACKGROUND.x1 = 0.0f; - DrawStyle::SELECTBACKGROUND.y1 = 0.2f; - DrawStyle::SELECTBACKGROUND.x2 = 1.1f; - DrawStyle::SELECTBACKGROUND.y2 = 0.8f; - - DrawStyle::TITLEBARBACKGROUND = DrawStyle::SELECTBACKGROUND; - - DrawStyle::LIGHTTEXT = DrawStyle(0xFFFFFFFF); - DrawStyle::DARKTEXT = DrawStyle(0xFF363636); - DrawStyle::DANGER = DrawStyle(200, 0, 0); - DrawStyle::BUTTONBACKGROUND = DrawStyle::SELECTBACKGROUND; - // two colours used as alterating backgrounds for individual programmes in EPG - DrawStyle::PROGRAMMEB = DrawStyle::SELECTBACKGROUND; - - - - DrawStyle::PROGRAMMEA = DrawStyle(0x7D000000); - DrawStyle::PROGRAMMEA.grad_col[0] = DrawStyle(0xFF353b50); - DrawStyle::PROGRAMMEA.grad_col[1] = DrawStyle(0xFF353b50); - DrawStyle::PROGRAMMEA.grad_col[2] = DrawStyle(0xFE999999); - DrawStyle::PROGRAMMEA.grad_pos[0] = 0.3f; - DrawStyle::PROGRAMMEA.grad_pos[1] = 0.9f; - DrawStyle::PROGRAMMEA.num_colors = 3; - DrawStyle::PROGRAMMEA.ft = DrawStyle::GradientLinear; - DrawStyle::PROGRAMMEA.x1 = 0.0f; - DrawStyle::PROGRAMMEA.y1 = 0.2f; - DrawStyle::PROGRAMMEA.x2 = 1.0f; - DrawStyle::PROGRAMMEA.y2 = 0.8f; - - - DrawStyle::NOPROGRAMME = DrawStyle(0xFF353b50); // no programme details colour - - DrawStyle::WALLPAPER = DrawStyle(0x00000000); // two colours used as alternating backgrounds for individual programmes in EPG - DrawStyle::WALLPAPER.grad_col[0] = DrawStyle(0x0012273f); - DrawStyle::WALLPAPER.num_colors = 1; - DrawStyle::WALLPAPER.ft = DrawStyle::GradientLinear; - DrawStyle::WALLPAPER.x1 = 0.0f; - DrawStyle::WALLPAPER.y1 = 0.0f; - DrawStyle::WALLPAPER.x2 = 0.0f; - DrawStyle::WALLPAPER.y2 = 1.0f; - - /* - Silly colours - - Colour Colour::VIDEOBLUE(250, 0, 0); - Colour Colour::VIEWBACKGROUND(100, 0, 100); - Colour Colour::TITLEBARBACKGROUND(100, 0, 200); - Colour Colour::SELECTHIGHLIGHT(240, 250, 180); - Colour Colour::LIGHTTEXT(255, 0, 255); - Colour Colour::DARKTEXT(0, 0, 255); - Colour Colour::DANGER(200, 200, 0); - Colour Colour::BUTTONBACKGROUND(255, 255, 255); - */ -} - -bool SkinFactory::InitSkin(int n) -{ - switch (n) - { - default: - case Classic: - InitDefaultSkin(); - break; -#ifdef GRADIENT_DRAWING - case ClassicEnhanced: - InitEnhancedSkin(); - break; - case NoopacityInspired: - InitNoopacityInspiredSkin(); - break; -#endif - } - - return true; -} diff --git a/colour.h b/colour.h deleted file mode 100644 index 9122f1b..0000000 --- a/colour.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - Copyright 2005 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef COLOUR_H -#define COLOUR_H - -#include "defines.h" - -class Colour -{ - public: - Colour() - { red = 0; green = 0; blue = 0; alpha = 255; } - - Colour(int Tred, int Tgreen, int Tblue) - { red = Tred; green = Tgreen; blue = Tblue; alpha = 255; } - - Colour(int Tred, int Tgreen, int Tblue, int Talpha) - { red = Tred; green = Tgreen; blue = Tblue; alpha = Talpha; } - - Colour(unsigned int color) - { - red = (color & 0x00ff0000) >> 16; - green = (color & 0x0000ff00) >> 8; - blue = (color & 0x000000ff); - alpha = (color & 0xff000000) >> 24; - } - - void set(int Tred, int Tgreen, int Tblue) - { red = Tred; green = Tgreen; blue = Tblue; alpha = 255; } - - void set(int Tred, int Tgreen, int Tblue, int Talpha) - { red = Tred; green = Tgreen; blue = Tblue; alpha = Talpha; } - - inline unsigned long rgba() const - { - return (alpha << 24) | (red << 16) | (green << 8) | blue; - } - - int red; - int green; - int blue; - int alpha; -}; - - -// TODO move to seperate File -class DrawStyle: public Colour -{ - public: - DrawStyle() - { red = 0; green = 0; blue = 0; alpha = 255; ft = Color; ct = Global; } - - DrawStyle(int Tred, int Tgreen, int Tblue) - { red = Tred; green = Tgreen; blue = Tblue; alpha = 255 ; ft = Color; ct = Global; } - - DrawStyle(int Tred, int Tgreen, int Tblue, int Talpha) - { red = Tred; green = Tgreen; blue = Tblue; alpha = Talpha; ft = Color; ct = Global; } - - DrawStyle(unsigned int color) - { - red = (color & 0x00ff0000) >> 16; - green = (color & 0x0000ff00) >> 8; - blue = (color & 0x000000ff); - alpha = (color & 0xff000000) >> 24; - ft = Color; ct = Global; - } - - DrawStyle(const Colour& c) - { - red = c.red; - green = c.green; - blue = c.blue; - alpha = c.alpha; - ft = Color; ct = Global; - } - - enum FillType - { - Color, - GradientLinear, - GradientRadial, - }; - - enum CoordType - { - Global, - Local - }; - - enum FillType ft; - enum CoordType ct; //not implemented yet - float x1, y1, x2, y2, r; // Parameter for gradient either relative to object or to global coordinate system - int num_colors; //max is 4, min is 0 - Colour grad_col[4]; - float grad_pos[3]; //Last position is alway 1.0 and first 0.0 - - static DrawStyle TRANSPARENT; - static DrawStyle WHITE; - static DrawStyle BLACK; - static DrawStyle RED; - static DrawStyle GREEN; - static DrawStyle YELLOW; - static DrawStyle BLUE; - static DrawStyle GREY; - static DrawStyle DARKGREY; - static DrawStyle VIDEOBLUE; - static DrawStyle VIEWBACKGROUND; - static DrawStyle VIEWTRANSPARENTBACKGROUND; - static DrawStyle LIVETVSYMBOLS; - static DrawStyle PROGRESSBAR; - static DrawStyle OSDBACKGROUND; - static DrawStyle TABVIEWBACKGROUND; - static DrawStyle TITLEBARBACKGROUND; - static DrawStyle SELECTBACKGROUND; - static DrawStyle SELECTHIGHLIGHT; - static DrawStyle SELECTDARKHIGHLIGHT; - static DrawStyle LIGHTTEXT; - static DrawStyle DARKTEXT; - static DrawStyle DANGER; - static DrawStyle BUTTONBACKGROUND; - static DrawStyle PROGRAMMEA; - static DrawStyle PROGRAMMEB; - static DrawStyle NOPROGRAMME; - static DrawStyle WALLPAPER; // this one is special, if transparent it means picture -}; - -#define COMPARE_TEST(x) if (rhs.x != lhs.x) { return rhs.x < lhs.x; } - -inline bool operator<(const DrawStyle& rhs, const DrawStyle& lhs) -{ - COMPARE_TEST(rgba()) - COMPARE_TEST(ft) - - if (rhs.ft == DrawStyle::Color) return false; - - COMPARE_TEST(num_colors) - COMPARE_TEST(x1) - COMPARE_TEST(x2) - COMPARE_TEST(y1) - COMPARE_TEST(y2) - - if (rhs.ft == DrawStyle::GradientRadial) COMPARE_TEST(r) - - for (int i = 0; i < lhs.num_colors; i++) - { - COMPARE_TEST(grad_col[i].rgba()) - - if (i > 0) COMPARE_TEST(grad_pos[i - 1]) - } - - COMPARE_TEST(ct) - - return false; -} - -#undef COMPARE_TEST - - -#define COMPARE_TEST(x) if (rhs.x!=lhs.x) return true; - -inline bool operator!=(const DrawStyle& rhs, const DrawStyle& lhs) -{ - COMPARE_TEST(rgba()) - COMPARE_TEST(ft) - - if (rhs.ft == DrawStyle::Color) return false; - - COMPARE_TEST(num_colors) - COMPARE_TEST(x1) - COMPARE_TEST(x2) - COMPARE_TEST(y1) - COMPARE_TEST(y2) - - if (rhs.ft == DrawStyle::GradientRadial) COMPARE_TEST(r) - - for (int i = 0; i < lhs.num_colors; i++) - { - COMPARE_TEST(grad_col[i].rgba()) - - if (i > 0) COMPARE_TEST(grad_pos[i - 1]) - } - - COMPARE_TEST(ct) - - return false; -} - -#undef COMPARE_TEST - - -class SkinFactory -{ - public: - - enum SkinNames - { -#ifdef GRADIENT_DRAWING - NoopacityInspired, - ClassicEnhanced, -#endif - Classic, - MaxSkins - }; - - static int getNumberofSkins(); - static const char ** getSkinNames(); - static bool InitSkin(int n); - - private: - static void InitDefaultSkin(); - static void InitEnhancedSkin(); - static void InitNoopacityInspiredSkin(); -}; - -#endif diff --git a/config.cc b/config.cc deleted file mode 100644 index 00e9365..0000000 --- a/config.cc +++ /dev/null @@ -1,170 +0,0 @@ -#include -#include -#include -#include - -// http://open-source-parsers.github.io/jsoncpp-docs/doxygen/namespacemembers.html - - -#include "config.h" - -Config* Config::instance = NULL; - -Config::Config() -: jconfigro(jconfig) -{ - instance = this; - applyDefaults(); -} - -Config::~Config() -{ - instance = NULL; -} - -Config* Config::getInstance() -{ - return instance; -} - -void Config::applyDefaults() -{ - // Insert the value only if it doesn't already exist - auto insertBool = [&] (const char* s, const char* k, bool v) { if (jconfig[s][k].isNull()) jconfig[s][k] = v; }; - auto insertString = [&] (const char* s, const char* k, const char* v) { if (jconfig[s][k].isNull()) jconfig[s][k] = v; }; - auto insertInt = [&] (const char* s, const char* k, int v) { if (jconfig[s][k].isNull()) jconfig[s][k] = v; }; - - insertBool("main", "daemonize", true); - insertInt("main", "start_to_live_tv", 0); - - insertBool("log", "enabled", false); - insertString("log", "filename", "stdout"); - insertString("log", "level", "debug"); - - #ifdef VOMP_PLATFORM_RASPBERRY - insertBool("input", "mod_cec_enabled", true); - #else - insertBool("input", "mod_cec_enabled", false); - #endif - - insertBool("input", "mod_udp_enabled", true); - insertBool("input", "mod_lirc_enabled", false); - - insertInt("input_udp", "port", 2000); - - insertInt("server-discovery", "prefer-ipv", 6); - - // Not in config.json.sample - VDR login always sets this - insertInt("subtitles", "default", 0); -} - -bool Config::loadFile() -{ - jconfig.clear(); - - std::ifstream configFile("config.json"); - if (configFile.is_open()) - { - Json::CharReaderBuilder builder; - builder["collectComments"] = false; - builder["allowTrailingCommas"] = true; // FIXME - std::string errs; - - bool ok = Json::parseFromStream(builder, configFile, &jconfig, &errs); - if (!ok) - { - std::cout << errs << std::endl; - return false; - } - } - - applyDefaults(); - return true; -} - -bool Config::getString(const std::string& section, const std::string& key, std::string& out) const -{ - Json::Value v = jconfigro[section][key]; - if (!v.isString()) return false; - out = v.asString(); - return true; -} - -bool Config::getInt(const std::string& section, const std::string& key, int& out) const -{ - Json::Value v = jconfigro[section][key]; - if (!v.isInt64()) return false; - out = static_cast(v.asInt64()); - return true; -} - -bool Config::getBool(const std::string& section, const std::string& key, bool& out) const -{ - Json::Value v = jconfigro[section][key]; - if (!v.isBool()) return false; - out = v.asBool(); - return true; -} -/* -bool Config::getBool(const char* section, const char* key, bool& out) const -{ - Json::Value v = jconfigro[section][key]; - if (!v.isBool()) return false; - out = v.asBool(); - return true; -}*/ - -void Config::dump() const -{ - std::cout << jconfigro << std::endl; -} - -bool Config::foreachInArray(const std::string& section, const std::string& key, std::function callback) const -{ - const Json::Value& v = jconfigro[section][key]; - if (!v.isArray()) return false; - - for(Json::Value::const_iterator i = v.begin(); i != v.end(); i++) - { - const Json::Value& jv = *i; - if (jv.isString()) - callback(jv.asString()); - } - - return true; -} - -bool Config::foreachPairInObject(const std::string& section, const std::string& key, std::function callback) const -{ - const Json::Value& v = jconfigro[section][key]; - if (!v.isObject()) return false; - - for(Json::Value::const_iterator i = v.begin(); i != v.end(); i++) - { - const Json::Value& jv = *i; - if (jv.isString()) - callback(i.key().asString(), jv.asString()); - } - - return true; -} - -void Config::set(const std::string& section, const std::string& key, const std::string& value) -{ - jconfig[section][key] = value; -} - -void Config::set(const std::string& section, const std::string& key, bool value) -{ - jconfig[section][key] = value; -} - -void Config::set(const std::string& section, const std::string& key, const char* value) -{ - jconfig[section][key] = value; -} - -void Config::set(const std::string& section, const std::string& key, int value) -{ - jconfig[section][key] = value; -} diff --git a/config.h b/config.h deleted file mode 100644 index 18a519f..0000000 --- a/config.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright 2021 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef CONFIG_H -#define CONFIG_H - -#include - -#include - -class Config -{ - public: - Config(); - ~Config(); - static Config* getInstance(); - - bool loadFile(); - - bool getString(const std::string& section, const std::string& key, std::string& out) const; - bool getInt(const std::string& section, const std::string& key, int& out) const; - bool getBool(const std::string& section, const std::string& key, bool& out) const; - void dump() const; - bool foreachInArray(const std::string& section, const std::string& key, std::function callback) const; - bool foreachPairInObject(const std::string& section, const std::string& key, std::function callback) const; - - void set(const std::string& section, const std::string& key, const std::string& value); - void set(const std::string& section, const std::string& key, bool value); - void set(const std::string& section, const std::string& key, const char* value); - void set(const std::string& section, const std::string& key, int value); - - private: - static Config* instance; - - void applyDefaults(); - - Json::Value jconfig; - const Json::Value& jconfigro; - -}; - -#endif diff --git a/config.json.sample b/config.json.sample deleted file mode 100644 index 3448df4..0000000 --- a/config.json.sample +++ /dev/null @@ -1,92 +0,0 @@ -/* Vomp local config file - - Using a local config.json file is optional. - This file shows all config options and their defaults, - where applicable. - - To use a local config, create config.json and copy in just the - settings you want to change. Place the file in the current working - directory for vompclient. - - Command line options override config.json. -*/ - -{ - "main": - { - "daemonize": true, - "start_to_live_tv": 1 // Channel number - }, - - "log": - { - "enabled": false, - "filename": "stdout", - "level": "debug" - }, - - "server": - { - // "server" has no defaults - // Normally vompclient will use IPv4 UDP broadcasts and IPv6 multicast to find servers - // Entering an address and optionally a port will disable discovery - - "address": "vdrserver.example.com", - "port": 3024 - }, - - "server-discovery": - { - // If exactly two servers are found by auto server location and they have the same - // name and port but different IP versions, prefer which? - "prefer-ipv": 6 - }, - - "input": - { - "mod_cec_enabled": true, - "mod_udp_enabled": true, - "mod_lirc_enabled": true - }, - - "input_udp": - { - "port": 2000 - } - - "input_lirc": - { - // input_lirc has no defaults - - // Use these two options: - - "lirc_ip": "192.0.2.0", /* Numeric IPv4 or IPv6 */ - "lirc_port": 8765, /* except this, this has a default */ - - // Or this one: - - "lirc_socket": "/run/lirc/lircd", - - // - - // List all the Lirc remote names to listen to here: - - "remotes": [ "lirc-remote-name-1", "lirc-remote-name-2" ], - - // Now create a section here for each Lirc remote. Map each Lirc button to vomp keys. - - "lirc-remote-name-1": - { - /* List all keys to be used by Vomp - On the left - the Lirc key name. On the right - the Vomp key name. See input.h (for now) */ - - "KEY_POWER": "POWER", - "KEY_MUTE": "MUTE" - // etc. - }, - - "lirc-remote-name-2": - { - } - } -} diff --git a/control.cc b/control.cc deleted file mode 100644 index d413498..0000000 --- a/control.cc +++ /dev/null @@ -1,1303 +0,0 @@ -/* - Copyright 2004-2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -// FIXME rename to Control and move stuff from main to here - -#ifndef WIN32 -#include // for reboot -#include -#include -#endif - -#include - -#ifdef WIN32 -#include "inputwin.h" -#endif - -#ifdef __ANDROID__ -#include "inputandroid.h" -#endif - -#include "led.h" -#include "video.h" -#include "audio.h" -#include "vdr.h" -#include "vvolume.h" -#include "vserverselect.h" -#include "vwelcome.h" -#include "vmute.h" -#include "colour.h" -#include "osd.h" -#include "i18n.h" -#include "timers.h" -#include "wol.h" -#include "vconnect.h" -#include "message.h" -#include "inputman.h" -#include "input.h" -#include "vinfo.h" -#include "boxx.h" -#include "boxstack.h" -#include "log.h" -#include "sleeptimer.h" -#include "wjpeg.h" -#include "osdvector.h" -#include "config.h" -#include "vvideolivetv.h" -#include "channel.h" -#include "imageloader.h" - - -#ifdef VOMP_PLATFORM_RASPBERRY - #include "ledraspberry.h" - #include "osdopenvg.h" - #include "videoomx.h" - #include "audioomx.h" -#endif - -#ifdef WIN32 - #include "windowsosd.h" - #ifdef WINDOWS_LEGACY - #include "osdwinpixel.h" - #else - #include "osdwinvector.h" - #endif - - #include "ledwin.h" - #include "videowin.h" - #include "audiowin.h" -#endif - -#include "control.h" - -static const char* TAG = "Control"; - -Control* Control::instance = NULL; - -Control::Control() -{ - if (instance) return; - instance = this; -} - -Control::~Control() -{ - flushMessageQueue(); - instance = NULL; -} - -Control* Control::getInstance() -{ - return instance; -} - -bool Control::init(bool tcrashed) -{ - if (initted) return false; - crashed = tcrashed; - logger = LogNT::getInstance(); - - SkinFactory::InitSkin(0); - - // FIXME All constructors first which do very little & don't rely on presence of other objects. - // Then all inits. Inits retrieve pointers to other objects. - - try - { - led = new Led_TYPE(); if (!led) throw 10; - if (!led->init(-1)) throw 11; // FIXME init(0) on Win32 - - timers = new Timers(); if (!timers) throw 20; - if (!timers->init()) throw 21; - - video = new Video_TYPE(); if (!video) throw 30; - if (!video->init(Video::PAL)) throw 31; - - audio = new Audio_TYPE(); if (!audio) throw 40; - if (!audio->init(Audio::MPEG2_PES)) throw 41; - - imageLoader = new ImageLoader(); if (!imageLoader) throw 50; - if (!imageLoader->init()) throw 51; - - osd = new Osd_TYPE(); if (!osd) throw 60; - if (!osd->init()) throw 61; - - vdr = new VDR(); if (!vdr) throw 70; - if (!vdr->init()) throw 71; - - boxstack = new BoxStack(); if (!boxstack) throw 80; - if (!boxstack->init()) throw 81; - - sleepTimer = new SleepTimer(); if (!sleepTimer) throw 90; - - wol = new Wol(); if (!wol) throw 100; - - inputMan = new InputMan(); if (!inputMan) throw 110; - if (!inputMan->init()) throw 111; - - } - catch (int e) - { - if (e == 10) logger->crit(TAG, "LED module failed to create"); - else if (e == 11) logger->crit(TAG, "LED module failed to initialise"); - else if (e == 20) logger->crit(TAG, "Timers module failed to create"); - else if (e == 21) logger->crit(TAG, "Timers module failed to initialise"); - else if (e == 30) logger->crit(TAG, "Video module failed to create"); - else if (e == 31) logger->crit(TAG, "Video module failed to initialise"); - else if (e == 40) logger->crit(TAG, "Audio module failed to create"); - else if (e == 41) logger->crit(TAG, "Audio module failed to initialise"); - else if (e == 50) logger->crit(TAG, "ImageLoader module failed to create"); - else if (e == 51) logger->crit(TAG, "ImageLoader module failed to initialise"); - else if (e == 60) logger->crit(TAG, "OSD module failed to create"); - else if (e == 61) logger->crit(TAG, "OSD module failed to initialise"); - else if (e == 70) logger->crit(TAG, "VDR module failed to create"); - else if (e == 71) logger->crit(TAG, "VDR module failed to initialise"); - else if (e == 80) logger->crit(TAG, "BoxStack module failed to create"); - else if (e == 81) logger->crit(TAG, "BoxStack module failed to initialise"); - else if (e == 90) logger->crit(TAG, "SleepTimer module failed to create"); - else if (e == 100) logger->crit(TAG, "WOL module failed to create"); - else if (e == 110) logger->crit(TAG, "InputMan module failed to create"); - else if (e == 111) logger->crit(TAG, "InputMan module failed to initialise"); - - switch(e) - { - case 111: - delete inputMan; - inputMan = NULL; - FALLTHROUGH - case 110: - delete wol; - wol = NULL; - FALLTHROUGH - case 100: - delete sleepTimer; - sleepTimer = NULL; - FALLTHROUGH - case 90: - boxstack->shutdown(); - FALLTHROUGH - case 81: - delete boxstack; - boxstack = NULL; - FALLTHROUGH - case 80: - vdr->shutdown(); - FALLTHROUGH - case 71: - delete vdr; - vdr = NULL; - FALLTHROUGH - case 70: - osd->shutdown(); - FALLTHROUGH - case 61: - delete osd; - osd = NULL; - FALLTHROUGH - case 60: - imageLoader->shutdown(); - FALLTHROUGH - case 51: - delete imageLoader; - imageLoader = NULL; - FALLTHROUGH - case 50: - audio->shutdown(); - FALLTHROUGH - case 41: - delete audio; - audio = NULL; - FALLTHROUGH - case 40: - video->shutdown(); - FALLTHROUGH - case 31: - delete video; - video = NULL; - FALLTHROUGH - case 30: - timers->shutdown(); - FALLTHROUGH - case 21: - delete timers; - timers = NULL; - FALLTHROUGH - case 20: - led->shutdown(); - FALLTHROUGH - case 11: - delete led; - led = NULL; - FALLTHROUGH - case 10: - FALLTHROUGH - ; - } - - return false; - } - - initted = true; - return true; -} - -void Control::shutdown() -{ - if (!initted) return; - initted = false; - - if (inputMan) - { - inputMan->shutdown(); - delete inputMan; - inputMan = NULL; - logger->info(TAG, "InputMan module shut down"); - } - - if (wol) - { - delete wol; - logger->info(TAG, "WOL module shut down"); - } - - if (sleepTimer) - { - delete sleepTimer; - sleepTimer = NULL; - logger->info(TAG, "SleepTimer module shut down"); - } - - if (boxstack) - { - boxstack->shutdown(); - delete boxstack; - boxstack = NULL; - logger->info(TAG, "BoxStack module shut down"); - } - - if (vdr) - { - vdr->shutdown(); - delete vdr; - vdr = NULL; - logger->info(TAG, "VDR module shut down"); - } - - if (osd) - { - osd->shutdown(); - delete osd; - osd = NULL; - logger->info(TAG, "OSD module shut down"); - } - - if (imageLoader) - { - imageLoader->shutdown(); - delete imageLoader; - imageLoader = NULL; - logger->info(TAG, "ImageLoader shut down"); - } - - if (audio) - { - audio->shutdown(); - delete audio; - audio = NULL; - logger->info(TAG, "Audio module shut down"); - } - - if (video) - { - video->shutdown(); - delete video; - video = NULL; - logger->info(TAG, "Video module shut down"); - } - - if (timers) - { - timers->shutdown(); - delete timers; - timers = NULL; - logger->info(TAG, "Timers module shut down"); - } - - if (led) - { - led->shutdown(); - delete led; - led = NULL; - logger->info(TAG, "LED module shut down"); - } -} - -void Control::stop() -{ - logger->info(TAG, "Request stop"); - - Message* m = new Message(); // break master loop - m->message = Message::SHUTDOWN; - m->p_to = Message::CONTROL; - postMessage(m); -} - -void Control::doWallpaper() -{ - // Blue background - Boxx* bbg = new Boxx(); - bbg->setSize(video->getScreenWidth(), video->getScreenHeight()); - bbg->createBuffer(); - bbg->fillColour(DrawStyle::WALLPAPER); - boxstack->add(bbg); - boxstack->update(bbg); - boxstack->remove(bbg); - - // Wallpaper - wallpaper = new Boxx(); - wallpaper->setSize(video->getScreenWidth(), video->getScreenHeight()); - wallpaper->createBuffer(); - wallpaper->setBackgroundColour(DrawStyle::WALLPAPER); - - wallpaper_pict = new WJpegTYPE(); - wallpaper_pict->setSize(video->getScreenWidth(), video->getScreenHeight()); - - if (video->getFormat() == Video::PAL) - { - logger->debug(TAG, "PAL wallpaper selected"); -#ifndef _MIPS_ARCH - wallpaper_pict->init("/wallpaperPAL.jpg"); -#else - wallpaper_pict->init("wallpaperPAL.jpg"); -#endif - } - else - { - logger->debug(TAG, "NTSC wallpaper selected"); - wallpaper_pict->init("/wallpaperNTSC.jpg"); - } - - if (DrawStyle::WALLPAPER.alpha) - wallpaper_pict->setVisible(true); - else - wallpaper_pict->setVisible(false); - - wallpaper->add(wallpaper_pict); - wallpaper->draw(); - - boxstack->add(wallpaper); - boxstack->update(wallpaper); - - OsdVector* osdv = dynamic_cast(Osd::getInstance()); - if (osdv) osdv->updateBackgroundColor(DrawStyle::WALLPAPER); -} - -void Control::run() -{ - if (!initted) return; - - // just in case - Video::getInstance()->signalOn(); - Led::getInstance()->on(); - - doWallpaper(); - - if (crashed) - { - buildCrashedBox(); - } - else - { - VConnect* vconnect = new VConnect(); // Deleted when VConnect messages Control, and is boxstack->remove()'d - boxstack->add(vconnect); - vconnect->run(); - } - - inputMan->start(); - - //logger->debug(TAG, "Setting log trace only mode"); - //logger->setTraceOnlyMode(false); - - messageLoopRun = true; - messageLoop(); - - inputMan->stop(); - - boxstack->removeAllExceptWallpaper(); - boxstack->remove(wallpaper); - delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL; -} - -void Control::dispatchMessage(Message* m) -{ - logger->debug(TAG, "processing message {}", m->message); - - if (m->p_to == Message::CONTROL) - { - switch(m->message) - { - case Message::SHUTDOWN: - { - messageLoopRun = false; - break; - } - case Message::STOP_PLAYBACK: - { - handleCommand(Input::STOP); // an odd way of doing it, but so simple - break; - } - case Message::VDR_CONNECTED: - { - doJustConnected(static_cast(m->from)); - break; - } - case Message::SCREENSHOT: - { - logger->info(TAG, "Screenshot Message arrived"); - Osd::getInstance()->screenShot("out.jpg"); - break; - } - case Message::CONNECTION_LOST: - { - doFromTheTop(true); - break; - } - case Message::INPUT_EVENT: - { - logger->info(TAG, "INPUT_EVENT {}", m->parameter); - - handleCommand(m->parameter); - break; - } - case Message::CHANGE_LANGUAGE: - { - boxstack->removeAllExceptWallpaper(); - boxstack->update(wallpaper); - I18n::initialize(); - if (!VDR::getInstance()->isConnected()) { connectionLost(); break; } - VWelcome* vw = new VWelcome(); - vw->draw(); - boxstack->add(vw); - boxstack->update(vw); - break; - } - case Message::LAST_VIEW_CLOSE: - { - // Shouldn't be done like this. Some generic message pass back from vinfo perhaps - if (crashed) - { - crashed = false; - doFromTheTop(false); - } - -// VWelcome* vw = new VWelcome(); -// vw->draw(); -// boxstack->add(vw); -// boxstack->update(vw); - - break; - } - } - } - else if (m->p_to == Message::BOXSTACK) - { - boxstack->processMessage(m); - } - else if (m->p_to == Message::MOUSE_RECEIVER) - { - logger->debug(TAG, "Sending mouse message to boxstack for dispatch"); - boxstack->processMessage(m); - } - - else - { - m->to->processMessage(m); - } - - logger->debug(TAG, "done processing message {}", m->message); -} - -void Control::handleCommand(int button) -{ - if (isStandby && (button != Input::POWER) - && (button != Input::POWERON) - && (button != Input::POWEROFF)) return; - - if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost - - // command was not handled - - switch(button) - { - case Input::VOLUMEUP: - case Input::VOLUMEDOWN: - { - if (inputMan->handlesVolume()) // CEC volume handler? - { - if (button == Input::VOLUMEDOWN) - inputMan->volumeDown(); - else - inputMan->volumeUp(); - } - else - { - VVolume* v = new VVolume(); - boxstack->add(v); - v->handleCommand(button); // this will draw+show - } - return; - } - case Input::MUTE: - { - if (inputMan->handlesVolume()) - { - inputMan->volumeMute(); - } - else - { - VMute* v = new VMute(); - v->draw(); - boxstack->add(v); - boxstack->update(v); - } - return; - } - case Input::POWER: - { - doStandby(); - return; - } - case Input::POWERON: - { - doPowerOn(); - return; - } - case Input::POWEROFF: - { - doPowerOff(); - return; - } - case Input::OK: - { - // FIXME - if (!connLost) return; // if connLost, handle Input::OK - doFromTheTop(false); - return; - } - case Input::GO: - { - logger->debug(TAG, "Handling sleeptimer go"); - sleepTimer->go(); - return; - } - } -} - -/* -void Control::sig1() -{ -#ifdef DEV - Message* m = new Message(); // break into master mutex - m->message = Message::SCREENSHOT; - m->p_to = Message::CONTROL; - postMessage(m); -#endif -} -*/ - -void Control::doStandby() -{ - if (isStandby) - { - doPowerOn(); - } - else - { - doPowerOff(); - } -} - - -void Control::doPowerOn() -{ - if (isStandby) - { - Video::getInstance()->signalOn(); - Led::getInstance()->on(); - InputMan::getInstance()->changePowerState(true); - isStandby = false; - - VConnect* vconnect = new VConnect(); - boxstack->add(vconnect); - vconnect->run(); - } -} - -void Control::doPowerOff() -{ - if (!isStandby) - { - VDR::getInstance()->shutdownVDR(); - boxstack->removeAllExceptWallpaper(); - Video::getInstance()->signalOff(); - boxstack->update(wallpaper); - - VDR::getInstance()->configSave("General", "Last Power State", "Off"); - logger->unsetExternLogger(); - VDR::getInstance()->disconnect(); - Led::getInstance()->off(); - InputMan::getInstance()->changePowerState(false); - isStandby = true; - sleepTimer->shutdown(); - } -} - -void Control::doFromTheTop(bool which) -{ - if (isStandby) return; - if (which) - { - if (connLost) - { - logger->info(TAG, "Connection lost dialog already present"); - return; - } - - logger->info(TAG, "Doing connection lost dialog"); - connLost = new VInfo(); - connLost->setSize(360, 200); - connLost->createBuffer(); - if (Video::getInstance()->getFormat() == Video::PAL) - connLost->setPosition(190, 170); - else - connLost->setPosition(180, 120); - connLost->setOneLiner(tr("Connection lost")); - connLost->setDropThrough(); - connLost->setBorderOn(1); - connLost->setTitleBarColour(DrawStyle::DANGER); - connLost->okButton(); - connLost->draw(); - boxstack->add(connLost); - boxstack->update(connLost); - - clearMQInputEvents(); - } - else - { - logger->unsetExternLogger(); - VDR::getInstance()->disconnect(); - boxstack->removeAllExceptWallpaper(); - boxstack->update(wallpaper); - connLost = NULL; - - flushMessageQueue(); - - // at this point, everything should be reset to first-go - - VConnect* vconnect = new VConnect(); // deleted eventually in boxstack - boxstack->add(vconnect); - vconnect->run(); - } -} - -void Control::clearMQInputEvents() -{ - std::lock_guard lg(messageQueueMutex); // Get the lock - - MQueueI i = messages.begin(); - while(i != messages.end()) - { - Message* m = *i; - if (m->message == Message::INPUT_EVENT) - { - delete m; - i = messages.erase(i); - } - else - { - ++i; - } - } -} - -void Control::doReboot() -{ - - logger->unsetExternLogger(); - VDR::getInstance()->disconnect(); - // just kill it... - logger->info(TAG, "Reboot"); -#ifndef WIN32 -#ifndef VOMP_HAS_EXIT - // some plattforms, want a proper deinitialisation of their hardware before reboot - Osd::getInstance()->shutdown(); - Audio::getInstance()->shutdown(); - Video::getInstance()->shutdown(); - InputMan::getInstance()->shutdown(); - - reboot(LINUX_REBOOT_CMD_RESTART); - // if reboot is not allowed -> stop - stop(); - - -#else - stop(); - -#ifdef __ANDROID__ - exit(0); -#endif - -#endif -#endif //Would we support this on windows? -} - -void Control::connectionLost() -{ - logger->unsetExternLogger(); - Message* m = new Message(); // break into master mutex - m->message = Message::CONNECTION_LOST; - m->p_to = Message::CONTROL; - postMessage(m); -} - -void Control::buildCrashedBox() -{ - VInfo* crash = new VInfo(); - crash->setSize(360, 250); - crash->createBuffer(); - if (Video::getInstance()->getFormat() == Video::PAL) - crash->setPosition(190, 146); - else - crash->setPosition(180, 96); - crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash."); - crash->setBorderOn(1); - crash->setTitleBarColour(DrawStyle::DANGER); - crash->okButton(); - crash->setExitable(); - crash->draw(); - boxstack->add(crash); - boxstack->update(crash); -} - -int Control::getLangPref(bool subtitle, const char* langcode) -{ - std::vector::iterator itty=langcodes.begin(); - char templangcode[4]; - templangcode[0] = langcode[0]; - templangcode[1] = langcode[1]; - templangcode[2] = langcode[2]; - templangcode[3] = '\0'; - int langpos = 0; - while (itty != langcodes.end()) - { - size_t pos = (*itty).langcode.find(templangcode); - if (pos != std::string::npos) - { - //vector::iterator itty2=langcodes.begin(); - for (unsigned int i = 0; i < langcodes.size(); i++) - { - int pref = 0; - if (subtitle) - pref = langcodes[i].subtitlepref; - else - pref = langcodes[i].audiopref; - if (pref < 0) break; - - if (subtitle) - { - if (langcodes[i].subtitlepref==langpos) return i; - } - else - { - if (langcodes[i].audiopref==langpos) return i; - } - } - break; - } - itty++; - langpos++; - } - return langcodes.size(); //neutral -} - -void Control::doJustConnected(VConnect* vconnect) -{ - I18n::initialize(); - if (!VDR::getInstance()->isConnected()) { connectionLost(); return; } - logger->info(TAG, "Entering doJustConnected"); - - boxstack->remove(vconnect); - - VInfo* vi = new VInfo(); - vi->setSize(400, 200); - vi->createBuffer(); - if (video->getFormat() == Video::PAL) - vi->setPosition(170, 200); - else - vi->setPosition(160, 150); - vi->setOneLiner(tr("Connected, loading config")); - vi->draw(); - boxstack->add(vi); - boxstack->update(vi); - - // FIXME make config system - - char* config; - - // See if we're supposed to do network logging - config = vdr->configLoad("Advanced", "Network logging"); - if (config && !STRCASECMP(config, "On")) - { - logger->info(TAG, "Turning on network logging"); - logger->setExternLogger(vdr); - } - else - { - logger->unsetExternLogger(); - logger->info(TAG, "Turned off network logging"); - } - if (config) delete[] config; - - config = vdr->configLoad("Advanced", "Skin Name"); - if (config) - { - const char **skinnames=SkinFactory::getSkinNames(); - for (int i=0;isetVisible(true); - else - wallpaper_pict->setVisible(false); - - wallpaper->draw(); - boxstack->update(wallpaper); - } - } - else - { - SkinFactory::InitSkin(0); - } - - // See if config says to override video format (PAL/NTSC) - config = vdr->configLoad("General", "Override Video Format"); - if (config) - { - logger->debug(TAG, "Override Video Format is present"); - - if ( (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL)) - || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC)) - || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M)) - || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J)) - ) - { - // Oh sheesh, need to switch format. Bye bye TV... - - // Take everything down - boxstack->removeAllExceptWallpaper(); - boxstack->remove(wallpaper); - delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL; - -#ifndef __ANDROID__ - osd->shutdown(); -#endif - video->shutdown(); - - // FIXME FIXME FIXME why do this? - inputMan->shutdown(); // need on raspberry shut not do any harm, hopefully - inputMan->init(); - - // Get video and osd back up with the new mode - if (!strcmp(config, "PAL")) - { - logger->debug(TAG, "Switching to PAL"); - video->init(Video::PAL); - } - else if (!strcmp(config, "NTSC")) - { - logger->debug(TAG, "Switching to NTSC"); - video->init(Video::NTSC); - } else if (!strcmp(config, "PAL_M")) - { - logger->debug(TAG, "Switching to PAL_M"); - video->init(Video::PAL_M); - } else if (!strcmp(config, "NTSC_J")) - { - logger->debug(TAG, "Switching to NTSC_J"); - video->init(Video::NTSC_J); - } - delete[] config; - -#ifndef __ANDROID__ - //we do not init twice - osd->init(); -#endif - - // Put the wallpaper back - doWallpaper(); - - // Re add the vinfo - vi = new VInfo(); - vi->setSize(400, 200); - vi->createBuffer(); - if (video->getFormat() == Video::PAL) - vi->setPosition(170, 200); - else - vi->setPosition(160, 150); - - vi->setOneLiner(tr("Connected, loading config")); - vi->draw(); - boxstack->add(vi); - boxstack->update(vi); - } - else - { - logger->debug(TAG, "Already in requested mode, or request was not 'PAL' or 'NTSC'"); - } - } - else - { - logger->debug(TAG, "Phew, no dangerous on-the-fly mode switching to do!"); - } - - // Power off if first boot and config says so - if (firstBoot) - { - firstBoot = false; - - logger->debug(TAG, "Load power after boot"); - - config = vdr->configLoad("General", "Power After Boot"); - - if (config) - { - if (!STRCASECMP(config, "On")) - { - logger->info(TAG, "Config says Power After Boot = On"); - } - else if (!STRCASECMP(config, "Off")) - { - logger->info(TAG, "Config says Power After Boot = Off"); - doStandby(); - delete[] config; - return; // quit here - } - else if (!STRCASECMP(config, "Last state")) - { - char* lastPowerState = vdr->configLoad("General", "Last Power State"); - if (lastPowerState) - { - if (!STRCASECMP(lastPowerState, "On")) - { - logger->info(TAG, "Config says Last Power State = On"); - } - else if (!STRCASECMP(lastPowerState, "Off")) - { - logger->info(TAG, "Config says Last Power State = Off"); - doStandby(); - delete[] config; - return; // quit here - } - else - { - logger->info(TAG, "Config General/Last Power State not understood"); - } - } - else - { - logger->info(TAG, "Config General/Last Power State not found"); - } - } - else - { - logger->info(TAG, "Config/Power After Boot not understood"); - } - delete[] config; - } - else - { - logger->info(TAG, "Config General/Power After Boot not found"); - } - } - - - // Go S-Video if config says so - - config = vdr->configLoad("TV", "Connection"); - - if (config) - { - if (!STRCASECMP(config, "S-Video")) - { - logger->info(TAG, "Switching to S-Video as Connection={}", config); - video->setConnection(Video::SVIDEO); - } else if (!STRCASECMP(config, "HDMI")) - { - logger->info(TAG, "Switching to HDMI as Connection={}", config); - video->setConnection(Video::HDMI); - } else if (!STRCASECMP(config, "HDMI3D")) - { - logger->info(TAG, "Switching to HDMI3D as Connection={}", config); - video->setConnection(Video::HDMI3D); - } - else - { - logger->info(TAG, "Switching to RGB/Composite as Connection={}", config); - video->setConnection(Video::COMPOSITERGB); - } - delete[] config; - } - else - { - logger->info(TAG, "Config TV/S-Video not found"); - } - - // Set to shutdown VDR if config says - - config = vdr->configLoad("General", "VDR shutdown"); - if (config) - { - if (!STRCASECMP(config, "On")) - { - logger->info(TAG, "Shutdown VDR when shutting down vomp"); - vdr->setVDRShutdown(true); - } - else if (!STRCASECMP(config, "Off")) - { - logger->info(TAG, "Shutdown only vomp"); - vdr->setVDRShutdown(false); - } - } - else - { - logger->info(TAG, "Default shutdown only vomp"); - vdr->setVDRShutdown(false); // Default - } - - // Get TV aspect ratio - - config = vdr->configLoad("TV", "Aspect"); - if (config) - { - if (!STRCASECMP(config, "16:9")) - { - logger->info(TAG, "/// Switching to TV aspect 16:9"); - video->setTVsize(Video::ASPECT16X9); - } - else - { - logger->info(TAG, "/// Switching to TV aspect 4:3"); - video->setTVsize(Video::ASPECT4X3); - } - delete[] config; - } - else - { - logger->info(TAG, "Config TV/Aspect type not found, going 4:3"); - video->setTVsize(Video::ASPECT4X3); - } - - config = vdr->configLoad("TV", "Widemode"); - if (config) - { - if (!STRCASECMP(config, "Letterbox")) - { - logger->info(TAG, "Setting letterbox mode"); - video->setMode(Video::LETTERBOX); - } - else - { - logger->info(TAG, "Setting chop-sides mode"); - video->setMode(Video::NORMAL); - } - delete[] config; - } - else - { -#ifdef __ANDROID__ - logger->info(TAG, "Config TV/Widemode not found, Setting letterbox mode"); - video->setMode(Video::LETTERBOX); -#else - logger->info(TAG, "Config TV/Widemode not found, Setting chop-sides mode"); - video->setMode(Video::NORMAL); -#endif - } - - config = vdr->configLoad("Advanced", "TCP receive window"); - if (config) - { - size_t newTCPsize = atoi(config); - delete[] config; - - logger->info(TAG, "Setting TCP window size %i", newTCPsize); - vdr->setReceiveWindow(newTCPsize); - } - else - { - logger->info(TAG, "TCP window size not found, setting 2048"); - if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default - } - - config = vdr->configLoad("Advanced", "Font Name"); - if (config) - { - Osd::getInstance()->setFont(config); - logger->info(TAG, "Setting Font to %s", config); - delete[] config; - - } - - - // Set recording list type - -#ifdef ADVANCED_MENUES - config = vdr->configLoad("Advanced", "Menu type"); - - if (config) - { - if (!STRCASECMP(config, "Advanced")) - { - logger->info(TAG, "Switching to Advanced menu"); - advMenus = true; - } - else - { - logger->info(TAG, "Switching to Classic menu"); - advMenus = false; - } - delete[] config; - } - else - { - logger->info(TAG, "Config General/menu type not found"); - advMenus = true; - } -#endif - - config = vdr->configLoad("Advanced", "Disable WOL"); - if (config) - { - if (!STRCASECMP(config, "Yes")) - { - logger->info(TAG, "Config says disable WOL"); - Wol::getInstance()->setEnabled(false); - } - else - { - logger->info(TAG, "Config says enable WOL"); - Wol::getInstance()->setEnabled(true); - } - - delete[] config; - } - else - { - logger->info(TAG, "By default, enable WOL"); - Wol::getInstance()->setEnabled(true); - } - /* device dependend config */ - audio->loadOptionsFromServer(vdr); - video->loadOptionsFromServer(vdr); - inputMan->loadOptionsFromServer(vdr); - - video->executePendingModeChanges(); - // config done - - // Save power state = on - - vdr->configSave("General", "Last Power State", "On"); - - // Make sure connection didn't die - if (!vdr->isConnected()) - { - Control::getInstance()->connectionLost(); - } - else - { - boxstack->remove(vi); - - VWelcome* vw = new VWelcome(); - vw->draw(); - boxstack->add(vw); - // No boxstack->update yet - - Config* localConfig = Config::getInstance(); - int startToLiveTV{}; - localConfig->getInt("main", "start_to_live_tv", startToLiveTV); - if (startToLiveTV) - { - std::shared_ptr chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO); - if (chanList && chanList->size()) - { - Channel* chan = NULL; - for (UINT i = 0; i < chanList->size(); i++) - { - if ((*chanList)[i]->number == static_cast(startToLiveTV)) - { - chan = (*chanList)[i]; - break; - } - } - if (chan) - { - VVideoLiveTV* v = new VVideoLiveTV(chanList, chan->number, NULL); - boxstack->add(v); - v->go(); - } - else - { - // Could not find channel, no VVideoLiveTV was made, update vw instead - boxstack->update(vw); - } - } - else - { - Control::getInstance()->connectionLost(); - } - } - else // Not starting to live TV - { - boxstack->update(vw); - } - - // Enter pre-keys here -// handleCommand(Input::OK); -// handleCommand(Input::THREE); -// handleCommand(Input::SIX); -// handleCommand(Input::UP); -// handleCommand(Input::OK); -// handleCommand(Input::OK); -// handleCommand(Input::PLAY); -// handleCommand(Input::DOWN); -// handleCommand(Input::DOWN); -// handleCommand(Input::DOWN); -// handleCommand(Input::RIGHT); -// handleCommand(Input::RED); - } -} diff --git a/control.h b/control.h deleted file mode 100644 index fc0ab74..0000000 --- a/control.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - Copyright 2004-2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef COMMAND_H -#define COMMAND_H - -#include -#include - -#include "defines.h" -#include "messagequeue.h" - -class VDR; -class VConnect; -class Message; -class InputMan; -class ImageLoader; -class Boxx; -class BoxStack; -class LogNT; -class VInfo; -class WJpeg; -class SleepTimer; -class Wol; -class Audio; -class Video; -class Osd; -class Timers; -class Led; - -struct ASLPref -{ - std::string langcode; - int audiopref; - int subtitlepref; -}; - -typedef std::vector ASLPrefList; - -class Control : public MessageQueue -{ - public: - Control(); - ~Control(); - static Control* getInstance(); - - bool init(bool crashed = false); - void shutdown(); - void run(); - void stop(); - void doReboot(); - void connectionLost(); - - void setAdvMenus(bool adv) { advMenus = adv; }; - bool isAdvMenus() { return advMenus; }; - int getLangPref(bool subtitle,const char* langcode); - ASLPrefList &getASLList() { return langcodes; }; - - private: - // I own: - Led* led{}; - Timers* timers{}; - Osd* osd{}; - Video* video{}; - Audio* audio{}; - VDR* vdr{}; - ImageLoader* imageLoader{}; - BoxStack* boxstack{}; - SleepTimer* sleepTimer{}; - Wol* wol{}; - InputMan* inputMan{}; - - - - void handleCommand(int); - void doStandby(); - void doPowerOn(); - void doPowerOff(); - void doJustConnected(VConnect* vconnect); - void doWallpaper(); - void doFromTheTop(bool which); // true - show vinfo,wait. false - del vinfo,restart - void buildCrashedBox(); -// void sig1(); - void clearMQInputEvents(); - - static Control* instance; - - LogNT* logger; - - bool initted{}; - bool isStandby{}; - bool firstBoot{true}; - Boxx* wallpaper{}; - WJpeg* wallpaper_pict{}; - VInfo* connLost{}; - bool crashed{}; - - bool advMenus{}; - ASLPrefList langcodes; - - void dispatchMessage(Message* m); -}; - -#endif diff --git a/defines.h b/defines.h deleted file mode 100644 index fb003f7..0000000 --- a/defines.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - Copyright 2004-2020 Chris Tallon - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -#ifndef DEFINES_H -#define DEFINES_H - -typedef unsigned char UCHAR; -typedef unsigned short USHORT; -typedef unsigned int UINT; -typedef unsigned long ULONG; -typedef unsigned long long ULLONG; - -#define OPTIONTYPE_TEXT 1 -#define OPTIONTYPE_INT 2 - -#define BENCHMARK_FPS - - -// Global useful functions - -long long getTimeMS(); - -#include - - -int getClockRealTime(struct timespec *tp); - -const std::string& getCommandLineServer(); - -//#define WINDOWS_LEGACY - -#ifdef WIN32 - - #define Led_TYPE LedWin - #define Video_TYPE VideoWin - - #define Thread_TYPE ThreadWin - #define ThreadID_TYPE unsigned int - #define VectorHandle void* - #define VECTOR_HANDLE_INIT NULL -#ifndef WINDOWS_LEGACY - #define Osd_TYPE OsdWinVector - #define Surface_TYPE SurfaceVector - #define GRADIENT_DRAWING - #define ADVANCED_MENUES // This is for special HD versions of our menus -#else - #define Osd_TYPE OsdWinPixel - #define Surface_TYPE SurfaceWin -#endif - - #define RemoteStartDev ""//No devices passed - -// FIXME - check C++ - I think some of these are in std:: now ? -// FIXME - Not on Windows. Obviously. Also _snprintf doesn't guarantee null termination. -// FIXME When the Windows code is upped to VS2015 use snprintf instead of _snprintf. - #define SNPRINTF _snprintf - #define VSNPRINTF _vsnprintf - #define STRCASECMP _stricmp - #define STRCASESTR StrStrI -/* #define STRTOULL _strtoui64 */ - #define STRTOUL strtoul - #define STRTOKR strtok_s - #define LOCALTIME_R(time, tm) (localtime_s(tm,time)) - - #define CLOSESOCKET closesocket - #define DEFAULT_TCP_WINDOWSIZE 2048 - #define DEFAULT_TCP_WINDOWSIZENR 2 /*=2048*/ - #define PLAYER_MAX_STREAMING_BUFFERS 120 // for video in uints of 50000 KB - - #define VOMP_HAS_EXIT - - #define FALLTHROUGH - -#else - - int min(UINT, int); -/*#ifdef _MIPS_ARCH - #define Surface_TYPE SurfaceDirectFB -#else - #define Surface_TYPE -#endif*/ -#ifdef __ANDROID__ - #define Thread_TYPE ThreadPAndroid - -#else - #define Thread_TYPE ThreadP - -#endif - #include - #define ThreadID_TYPE pthread_t - - #define SNPRINTF snprintf - #define VSNPRINTF vsnprintf - #define STRCASECMP strcasecmp - #define STRCASESTR strcasestr - #define STRTOUL strtoul - #define STRTOKR strtok_r - #define LOCALTIME_R(time, tm) (localtime_r(time, tm)) - - - #define CLOSESOCKET close - -// add here defines for plattform specific objects -#ifdef VOMP_PLATFORM_RASPBERRY - #define Remote_TYPE InputLinux // Generic Remote under Linux (Konsole!, not X) will support in the end: - #define RemoteStartDev ""//No devices passed - - // Keyboard - // remotes under /dev/event - // HDMI CEC - //lirc? - #define Led_TYPE LedRaspberry //this is device dependent - #define Osd_TYPE OsdOpenVG // This OpenGL ES 2.0, in the moment only for raspberry, but might be splitted for other devices - #define Audio_TYPE AudioOMX // This is Audio based on OpenMax and libav for decoding - #define Video_TYPE VideoOMX // This is Video based on OpenMax - - - - #define VPE_OMX_SUPPORT // Activate support for hardware codec using openmax il - #define VPE_OMX_H264_DECODER "OMX.broadcom.video_decode" - #define VPE_OMX_MPEG2_DECODER "OMX.broadcom.video_decode" - #define VPE_OMX_VIDEO_SCHED "OMX.broadcom.video_scheduler" - #define VPE_OMX_VIDEO_REND "OMX.broadcom.video_render" - #define VPE_OMX_VIDEO_DEINTERLACE "OMX.broadcom.image_fx" - #define VPE_OMX_CLOCK "OMX.broadcom.clock" - #define VPE_OMX_AUDIO_DECODER "OMX.broadcom.audio_decode" - #define VPE_OMX_AUDIO_REND "OMX.broadcom.audio_render" - #define VPE_OMX_IMAGE_DECODER "OMX.broadcom.image_decode" - #define VPE_OMX_EGL_REND "OMX.broadcom.egl_render" - - //#define VPE_LIBAV_SUPPORT - // #define VPE_LIBAV_MPEG2_TRANSCODING - - #define DEFAULT_TCP_WINDOWSIZE 0 - #define DEFAULT_TCP_WINDOWSIZENR 0 /*=2048*/ - #define PLAYER_MAX_STREAMING_BUFFERS 120 // for video in uints of 50000 KB - #define TV_NORM_SWITCHABLE - #define HANDLE_VT_SWITCHING - #define GRADIENT_DRAWING - #define ADVANCED_MENUES // This is for special HD versions of our menus - #define VectorHandle unsigned int - #define VECTOR_HANDLE_INIT 0 - - - #define PICTURE_DECODER_MAGICK - #define PICTURE_DECODER_OMX - - #define VOMP_LINUX_CLOCK CLOCK_MONOTONIC - -#define FALLTHROUGH [[fallthrough]]; - -#endif -#ifdef VOMP_PLATTFORM_MVP // FIXME OBSOLETE - #define Remote_TYPE RemoteMVP - #define RemoteStartDev "/dev/rawir" - #define Led_TYPE - #define Osd_TYPE - #define Audio_TYPE - #define Video_TYPE - #define Surface_TYPE - #define DEFAULT_TCP_WINDOWSIZE 2048 /*=2048*/ - #define DEFAULT_TCP_WINDOWSIZENR 2 /*=2048*/ - #define PLAYER_MAX_STREAMING_BUFFERS 11 // for video in uints of 50000 KB - #define PAL_WSS - - #define VOMP_MEDIAPLAYER - #define VOMP_LINUX_CLOCK CLOCK_REALTIME - - #define VectorHandle void* - #define VECTOR_HANDLE_INIT NULL - -#endif - -#ifdef VOMP_PLATTFORM_NMT // This was the attempt to port vomp to nmt, it failed but maybe the code is useful at some time - #define Remote_TYPE RemoteLirc - #define RemoteStartDev "/dev/lircd" - #define Led_TYPE LedMVP - #define Osd_TYPE OsdDirectFB - #define Audio_TYPE AudioNMT - #define Video_TYPE VideoNMT - #define Surface_TYPE SurfaceDirectFB //deprecated - #define DEFAULT_TCP_WINDOWSIZE 2048 - #define DEFAULT_TCP_WINDOWSIZENR 2 /*=2048*/ - #define PLAYER_MAX_STREAMING_BUFFERS 11 // for video in uints of 50000 KB - - #define VOMP_LINUX_CLOCK CLOCK_REALTIME - -#endif - -#endif - -/* -typedef struct -{ - UINT id; // Used for working out what has changed at the end - char *title; // Name of the option - char *configSection; // Which section of the config file - char *configParam; // Parameter name in the config file - UINT optionType; // 1 for text, 2 for int - UINT optionCount; // How many choices? - UINT defaultOption; // Serial of the default choice (base 0), or actual option in int mode - int startInt; // Starting int for int mode - const char * const * options; // Text for the options (null for int mode) -} OPTIONDATA; -*/ - -#endif diff --git a/demuxer.cc b/demuxer.cc deleted file mode 100644 index 075a8b9..0000000 --- a/demuxer.cc +++ /dev/null @@ -1,1248 +0,0 @@ -/* - Copyright 2005-2008 Mark Calderbank - Copyright 2007 Marten Richter (AC3 support) - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "demuxer.h" - -#include "callback.h" -#include "dvbsubtitles.h" -#include "log.h" - -#include -#include - -#include - -#define DEMUXER_SEQ_HEAD 0x000001B3 -#define DEMUXER_PIC_HEAD 0x00000101 -#define DEMUXER_SEQ_EXT_HEAD 0x000001B5 - -#define DEMUXER_H264_ACCESS_UNIT 0x00000109 -#define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107 -#define DEMUXER_H264_SUB_ENHANCEMENT_INF 0x00000106 -#define DEMUXER_H264_CODED_SLICE_IDR 0x00000105 -#define DEMUXER_H264_CODED_SLICE_NON_IDR 0x00000101 - -#define SEEK_THRESHOLD 150000 // About 1.5 seconds - -static const char* TAG = "Demuxer"; - -// Statics -const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 }; -Demuxer* Demuxer::instance = NULL; - -class NALUUnit { -public: - NALUUnit(const UCHAR* buf,UINT length_buf); - ~NALUUnit(); - -inline UINT getBits(UINT num_bits); - UINT getUe(); - int getSe(); - bool isEonalu() {return eonalu;}; - int getPos(){return pos;}; - -protected: - UCHAR* nalu_buf; - UINT nalu_length; - UINT pos; - UCHAR bit_pos; - UCHAR working_byte; - UINT last_bytes; - bool eonalu; -}; - -NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf) -{ - nalu_length=0; - nalu_buf=NULL; - pos=0; - bit_pos=0; - working_byte=0; - last_bytes=0; - eonalu=false; - - UINT nalu_start=0; - UINT nalu_end=0; - UINT pattern =(((UINT)buf[ 0] << 16) | - ((UINT)buf[1] << 8) | - (UINT)buf[2] ); - nalu_start=3; - while (pattern != 0x000001) - { - if (++nalu_start >= length_buf) return; - pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF; - } - nalu_end=nalu_start+1; - if (nalu_end >= length_buf) return; // input buffer too small. corrupt data? ignore. - pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF; - - while (pattern != 0x000001 && pattern != 0x000000) - { - if (++nalu_end >= length_buf) { nalu_end+=3;break;}; - pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF; - } - nalu_end-=3; - nalu_end=std::min(length_buf-1,nalu_end); - if (nalu_end <= nalu_start) return; // input buffer too small. corrupt data? ignore. - nalu_length=nalu_end-nalu_start; - nalu_buf=(UCHAR*)malloc(nalu_length); - memcpy(nalu_buf,buf+nalu_start,nalu_length); - pos=1; -} - -NALUUnit::~NALUUnit() -{ - if (nalu_buf) free(nalu_buf); -} - -inline UINT NALUUnit::getBits(UINT num_bits) -{ - if (num_bits==0) return 0; //??? - UINT remain_bits=num_bits; - UINT work=0; - //May be slow, but should work! - while (remain_bits>0) { - if (bit_pos==0) { - if (pos(8-bit_pos)); - work=work <>bit_pos) & (0xFF>>(8-fetch_bits))); - work|=(working_byte &(0xFF>>(bit_pos)))>>(8-fetch_bits-bit_pos); - remain_bits-=fetch_bits; - bit_pos=(bit_pos+fetch_bits)%8; - } - return work; -} - -UINT NALUUnit::getUe() -{ - int leadbits=-1; - bool bit; - for( bit = 0; !bit && !eonalu; leadbits++ ) - bit = getBits(1); - if (eonalu) return 0; - return ((1 << leadbits)-1)+getBits(leadbits); -} - -int NALUUnit::getSe() -{ - UINT input=getUe(); - if (input==0) return 0; - int output=((input+1)>>1); - if (input & 0x1) output*=-1; - return output; -} - - - -static const int PESPacket_initial_size = 2000; - -// PESPacket methods -PESPacket::PESPacket() -{ - data_size = PESPacket_initial_size; - data = (UCHAR*)malloc(data_size); - data[0] = 0x00; - data[1] = 0x00; - data[2] = 0x01; - init(0); -} - -PESPacket::PESPacket(const PESPacket& packet) -{ - copyFrom(packet); -} - -PESPacket& PESPacket::operator=(const PESPacket& packet) -{ - if (this != &packet) - { - if (data) free(data); - copyFrom(packet); - } - return *this; -} - -PESPacket::~PESPacket() -{ - if (data) free(data); -} - -void PESPacket::copyFrom(const PESPacket& packet) -{ - length = packet.length; - size = packet.size; - packetType = packet.packetType; - substream = packet.substream; - seq_header = packet.seq_header; - data_size = size; - data = (UCHAR*)malloc(data_size); - memcpy(data, packet.data, data_size); -} - -void PESPacket::init(UCHAR type, UCHAR sub) -{ - length = 0; - size = 6; - data[4] = data[5] = 0; - data[3] = type; - packetType = type; - substream = sub; - seq_header = 1; // Unknown seq_header status - -} - -void PESPacket::truncate() -{ - init(packetType,substream); -} - - - -int PESPacket::write(const UCHAR *buf, int len) -{ - - - if (size + len > 0x10000) return 0; - if (size + len > data_size) - { // Reallocate - UINT new_data_size = std::max(data_size + data_size / 2, data_size + len); - if (new_data_size > 0x10000) new_data_size = 0x10000; - data_size = new_data_size; - data = (UCHAR*)realloc(data, data_size); - } - memcpy(data + size, buf, len); - length += len; - size += len; - data[4] = (length >> 8); - data[5] = (length & 0xFF); - // We have added data - reset seq_header indicator if necessary - if (seq_header == 0) seq_header = 1; // Reset to 'unknown' - return 1; -} - -ULLONG PESPacket::getPTS() const -{ - if ( ( (packetType >= Demuxer::PESTYPE_AUD0 && - packetType <= Demuxer::PESTYPE_AUDMAX) - || - (packetType >= Demuxer::PESTYPE_VID0 && - packetType <= Demuxer::PESTYPE_VIDMAX) - || - packetType == Demuxer::PESTYPE_PRIVATE_1 - ) - && size >= 14 && data[7] & 0x80) - { - return ( (ULLONG)(data[ 9] & 0x0E) << 29) | - ( (ULLONG)(data[10]) << 22 ) | - ( (ULLONG)(data[11] & 0xFE) << 14 ) | - ( (ULLONG)(data[12]) << 7 ) | - ( (ULLONG)(data[13] & 0xFE) >> 1 ); - } - else return PTS_INVALID; -} - -UCHAR PESPacket::operator[] (UINT index) const -{ - if (index >= size) - return 0; - else - return data[index]; -} - -UINT PESPacket::findPictureHeader(bool h264) const -{ - if (size < 12) return 0; - UINT pattern = ( ((UINT)data[ 8] << 24) | - ((UINT)data[ 9] << 16) | - ((UINT)data[10] << 8) | - (UINT)data[11] ); - UINT pos = 11; - if (h264) { - - while (pattern != DEMUXER_H264_ACCESS_UNIT) - { - if (++pos >= size) return 0; - pattern = (pattern << 8) | data[pos]; - } - return pos-3; - } else { - while (pattern != DEMUXER_PIC_HEAD) - { - if (++pos >= size) return 0; - pattern = (pattern << 8) | data[pos]; - } - return pos-3; - } -} - -UINT PESPacket::countPictureHeaders(bool h264, struct PictCountInfo& pinfo) const -{ - if (size < 12) return 0; - UINT pattern = ( ((UINT)data[ 8] << 24) | - ((UINT)data[ 9] << 16) | - ((UINT)data[10] << 8) | - (UINT)data[11] ); - UINT pos = 11; - UINT count=0; - if (h264) { - //inspired by vdr algorithm for frame couting by Klaus Schmidinger - while (poserror(TAG, - "Has slice %d %d %d %d %d",pinfo.hasaccessunit, pinfo.hassps,pinfo.frame_mbs_only_flag,pinfo.separate_color_plane_flag, - pinfo.log2_max_frame_num);*/ - if (pinfo.hasaccessunit && pinfo.hassps) { - - NALUUnit nalu(data+pos-3,getSize()-pos+3); - nalu.getUe();// first_mb_in_slice - nalu.getUe();//sliectype - if (!pinfo.frame_mbs_only_flag) { - nalu.getUe(); //pic_paramter_set_id - if (pinfo.separate_color_plane_flag) nalu.getBits(2); - nalu.getBits(pinfo.log2_max_frame_num); - //if (!frame_mbs_only_flag) - if (nalu.getBits(1)) { //field_picture - if (!nalu.getBits(1)) { //bottom_field - count++; - } - } else count++; - - } else count++; - pattern=0xFFFFFF; - pos+=nalu.getPos(); - pinfo.hasaccessunit=false; - } - } - } - } - return count; - } else { - while (pos= size) - { - seq_header = 0; - return 0; - } - pattern = (pattern << 8) | data[pos]; - } - seq_header = pos - 3; - } - else - { - while (pattern != DEMUXER_SEQ_HEAD) - { - if (++pos >= size) - { - seq_header = 0; - return 0; - } - pattern = (pattern << 8) | data[pos]; - } - seq_header = pos - 3; - } - return seq_header; -} - -UINT PESPacket::findSeqExtHeader(bool h264) const -{ - if (seq_header != 1) return seq_header; - if (size < 12) return 0; - UINT pattern = ( ((UINT)data[ 8] << 24) | - ((UINT)data[ 9] << 16) | - ((UINT)data[10] << 8) | - (UINT)data[11] ); - UINT pos = 11; - if (h264) { - while ((pattern & 0xFFFFFF1F) != DEMUXER_H264_SUB_ENHANCEMENT_INF) - { - if (++pos >= size) - { - seq_header = 0; - return 0; - } - pattern = (pattern << 8) | data[pos]; - } - seq_header = pos - 3; - } - else - { - while (pattern != DEMUXER_SEQ_EXT_HEAD && (data[pos+1]&0xf0)!=0x10) - { - if (++pos >= (size-1)) - { - seq_header = 0; - return 0; - } - pattern = (pattern << 8) | data[pos]; - } - seq_header = pos - 3; - } - return seq_header; -} - -// Demuxer methods -Demuxer::Demuxer() -{ - if (instance) return; - instance = this; - initted = false; - callback = NULL; - arcnt = 0; - vid_seeking = aud_seeking = false; - video_pts = audio_pts = 0; - ispre_1_3_19 = false; - packetnum=0; - h264 = false; - fps = 25.0; - astreamtype=4; - livetv=false; -} - -Demuxer::~Demuxer() -{ - shutdown(); - instance = NULL; -} - -Demuxer* Demuxer::getInstance() -{ - return instance; -} - -int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext, - ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,double infps, DVBSubtitles* tsubtitles) -{ - if (!initted) - { - if ( !videostream.init(video, demuxMemoryV) || - !audiostream.init(audio, demuxMemoryA) || - !teletextstream.init(teletext, demuxMemoryT)) - { - LogNT::getInstance()->crit(TAG, "Failed to initialize demuxer"); - shutdown(); - return 0; - } - } - if (teletext) { - isteletextdecoded = true; - } else { - isteletextdecoded = false; - } - fps=infps; - reset(); - initted = true; - subtitles = tsubtitles; - callback = tcallback; - return 1; -} - -void Demuxer::reset() -{ - LogNT::getInstance()->debug(TAG, "Reset called"); - flush(); - video_current = audio_current = teletext_current = subtitle_current = -1; - horizontal_size = vertical_size = 0; - interlaced=true; // default is true - aspect_ratio = (enum AspectRatio) 0; - parx=1; - pary=1; - frame_rate = bit_rate = 0; - ispre_1_3_19 = false; - h264 = false; - packetnum=0; - astreamtype=4; - livetv=false; - - for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++) - { - avail_mpaudchan[i] = false; - } - for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++) - { - avail_ac3audchan[i] = false; - } - for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++) - { - avail_dvbsubtitlechan[i] = false; - } -} - -int Demuxer::shutdown() -{ - videostream.shutdown(); - audiostream.shutdown(); - teletextstream.shutdown(); - initted = false; - return 1; -} - -void Demuxer::flush() -{ - LogNT::getInstance()->debug(TAG, "Flush called"); - - videostream.flush(); - audiostream.flush(); - teletextstream.flush(); -} - -void Demuxer::flushAudio() -{ - audiostream.flush(); -} - -void Demuxer::seek() -{ - vid_seeking = aud_seeking = true; - video_pts = audio_pts = teletext_pts = 0; -} - -void Demuxer::setAudioStream(int id) -{ - audio_current = id; -} - -void Demuxer::setVideoStream(int id) -{ - video_current = id; -} - -void Demuxer::setTeletextStream(int id) -{ - teletext_current = id; -} - -void Demuxer::setDVBSubtitleStream(int id) -{ - subtitle_current = id; -} - -void Demuxer::setAspectRatio(enum AspectRatio ar, int taspectx, int taspecty) -{ - if ((aspect_ratio != ar) || (parx != taspectx) || (pary != taspecty) ) - { - LogNT::getInstance()->debug(TAG, "Aspect ratio difference signalled"); - if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal - { - arcnt = 0; - aspect_ratio = ar; - parx=taspectx; - pary=taspecty; - if (callback) callback->call(this); - } - } - else - arcnt = 0; -} - -bool Demuxer::writeAudio(bool * dataavail) -{ - return audiostream.drain(dataavail); -} - -bool Demuxer::writeVideo(bool * dataavail) -{ - return videostream.drain(dataavail); -} - -bool Demuxer::writeTeletext(bool * dataavail) -{ - return teletextstream.drain(dataavail); -} - -bool Demuxer::submitPacket(PESPacket& packet) -{ - UINT sent = 0; - UCHAR packet_type = packet.getPacketType(); - const UCHAR* packetdata = packet.getData(); - if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX) - { - if (video_current == -1) video_current = packet_type; - if (video_current == packet_type && !vid_seeking) - { - sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum); - if (sent) packetnum++; - } - else - sent = packet.getSize(); - } - else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX) - { - - if (audio_current == -1) audio_current = packet_type; - avail_mpaudchan[packet_type - PESTYPE_AUD0] = true; - if (audio_current == packet_type && !aud_seeking) - { - UCHAR type=MPTYPE_MPEG_AUDIO; - switch (astreamtype) - { - case 3: - case 4: - type=MPTYPE_MPEG_AUDIO; break; - case 0x11: - type=MPTYPE_AAC_LATM; break; - }; - sent = audiostream.put(&packetdata[0], packet.getSize(), type,packetnum); - if (sent) packetnum++; - } - else - sent = packet.getSize(); - } - else if (packet_type == PESTYPE_PRIVATE_1 && - packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 && - packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX) - { - avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true; - if (packet.getSubstream() == audio_current) - { - sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19 || livetv)? MPTYPE_AC3_PRE13 : MPTYPE_AC3,packetnum); - if (sent) packetnum++; - } - else - { - sent = packet.getSize(); - } - } - else if (packet_type == PESTYPE_PRIVATE_1 && - packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 && - packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX) - { - avail_dvbsubtitlechan[packet.getSubstream()-PESTYPE_SUBSTREAM_DVBSUBTITLE0]=true; - if (subtitle_current == -1) subtitle_current = packet.getSubstream(); - if (subtitles && packet.getSubstream()==subtitle_current) - { - subtitles->put(packet); - } - sent = packet.getSize(); - } - else if (isteletextdecoded && packet_type == PESTYPE_PRIVATE_1 && - packet.getSubstream() >= PESTYPE_SUBSTREAM_TELETEXT0 && - packet.getSubstream() <= PESTYPE_SUBSTREAM_TELETEXTMAX) - { - - if (teletext_current == -1) teletext_current = packet.getSubstream(); - if (teletext_current == packet.getSubstream()) - { - sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum); - } - else - { - sent = packet.getSize(); - } - } - else - { - sent = packet.getSize(); - } - - if (sent < packet.getSize()) // Stream is full. - return false; - else - return true; -} - -void Demuxer::parsePacketDetails(PESPacket& packet) -{ - if (packet.getPacketType() >= PESTYPE_AUD0 && - packet.getPacketType() <= PESTYPE_AUDMAX) - { - // Extract audio PTS if it exists - if (packet.hasPTS()) - { - audio_pts = packet.getPTS(); - // We continue to seek on the audio if the video PTS that we - // are trying to match is ahead of the audio PTS by at most - // SEEK_THRESHOLD. We consider the possibility of PTS wrap. - if (aud_seeking && !vid_seeking && - !( (video_pts_seek > audio_pts && - video_pts_seek - audio_pts < SEEK_THRESHOLD) - || - (video_pts_seek < audio_pts && - video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) )) - { - aud_seeking = 0; - LogNT::getInstance()->debug(TAG, "Leaving audio sync: Audio PTS = {}", audio_pts); - } - } - } - else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream - { - if (!livetv) { - //Inspired by vdr's device.c - int payload_begin = packet[8]+9; - unsigned char substream_id = packet[payload_begin]; - unsigned char substream_type = substream_id & 0xF0; - unsigned char substream_index = substream_id & 0x1F; - pre_1_3_19_Recording: //This is for old recordings stuff and live TV - if (ispre_1_3_19) - { - int old_substream=packet.getSubstream(); - if (old_substream){ //someone else already set it, this is live tv - substream_id = old_substream; - substream_type = substream_id & 0xF0; - substream_index = substream_id & 0x1F; - } else { - substream_id = PESTYPE_PRIVATE_1; - substream_type = 0x80; - substream_index = 0; - } - - } - switch (substream_type) - { - case 0x20://SPU - case 0x30://SPU - packet.setSubstream(substream_id); - break; - case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there? - break; - case 0x80: //ac3, currently only one ac3 track per recording supported - packet.setSubstream(substream_type+substream_index); - - // Extract audio PTS if it exists - if (packet.hasPTS()) - { - audio_pts = packet.getPTS(); - // We continue to seek on the audio if the video PTS that we - // are trying to match is ahead of the audio PTS by at most - // SEEK_THRESHOLD. We consider the possibility of PTS wrap. - if (aud_seeking && !vid_seeking && - !( (video_pts_seek > audio_pts && - video_pts_seek - audio_pts < SEEK_THRESHOLD) - || - (video_pts_seek < audio_pts && - video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) )) - { - aud_seeking = 0; - LogNT::getInstance()->debug(TAG, "Leaving audio sync: Audio PTS = {}", audio_pts); - } - } - break; - case 0x10: //Teletext Is this correct? - packet.setSubstream(substream_id); - // Extract teletxt PTS if it exists - if (packet.hasPTS()) - { - teletext_pts = packet.getPTS(); - } - break; - default: - if (!ispre_1_3_19) - { - ispre_1_3_19=true; //switching to compat mode and live tv mode - goto pre_1_3_19_Recording; - } - else - { - packet.setSubstream(0); - } - break; - } - } - } - else if (packet.getPacketType() >= PESTYPE_VID0 && - packet.getPacketType() <= PESTYPE_VIDMAX) - { - // Extract video PTS if it exists - if (packet.hasPTS()) video_pts = packet.getPTS(); - - // If there is a sequence header, extract information - UINT pos = packet.findSeqHeader(h264); - if (pos > 1) - { - if (!h264) { - pos += 4; - if (pos+6 >= packet.getSize()) return; - horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4); - - vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2]; - - enum AspectRatio aspect=(enum AspectRatio)(packet[pos+3] >> 4); - int aspectx=1; - int aspecty=1; - const int aspectDAR[]={0,1,1,1,4,3,16,9,221,100}; - int aspectDARx=aspectDAR[aspect*2]; - int aspectDARy=aspectDAR[aspect*2+1]; - - aspectx=aspectDARx*vertical_size; - aspecty=aspectDARy*horizontal_size; - - int commona; - int commonb; - // LogNT::getInstance()->debug(TAG, "PAR test1 {} {} {} {}", aspectx, aspecty, commona, commonb); - commona=aspectx; - commonb=aspecty; - - while (commonb) { - int temp=commonb; - commonb=commona%commonb; - commona=temp; - } - aspectx=aspectx/commona; - aspecty=aspecty/commona; - //LogNT::getInstance()->debug(TAG, "PAR test2 {} {} {} {} {} {} {}", aspectx,aspecty,aspectDARx,aspectDARy,horizontal_size,vertical_size,commona); - - setAspectRatio(aspect,aspectx,aspecty); - frame_rate = packet[pos+3] & 0x0f; - if (frame_rate >= 1 && frame_rate <= 8) - frame_rate = FrameRates[frame_rate]; - else - frame_rate = 0; - bit_rate = ((int)packet[pos+4] << 10) | - ((int)packet[pos+5] << 2) | - ((int)packet[pos+6] >> 6); - } - else - { - /* Chris and Mark I know this is ugly, should we move this to a method of PESPacket or to NALUUnit what would be better? - This looks so ugly since the header includes variable length parts and I have to parse through the whole header to get the wanted information*/ - NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos); - profile=nalu.getBits(8); - nalu.getBits(8); //constraints - nalu.getBits(8); //level_idc - nalu.getUe(); //seq_parameter_set_id - int chroma=1; - if (profile==100 || profile==110 || profile==122 || profile==144) - { - chroma=nalu.getUe(); - if (chroma==3) - { - nalu.getBits(1); - } - nalu.getUe(); //bit depth lume - nalu.getUe(); //bit depth chrome - nalu.getBits(1); - if (nalu.getBits(1)) - { - for (int i=0;i<8;i++){ - if (nalu.getBits(1)) - { - if (i<6) - { - UINT lastscale=8; - UINT nextscale=8; - for (int j=0;j<16;j++) { - if (nextscale!=0) { - UINT delta=nalu.getSe(); - nextscale=(lastscale+delta+256)%256; - } - lastscale=(nextscale==0)?lastscale:nextscale; - } - } - else - { - UINT lastscale=8; - UINT nextscale=8; - for (int j=0;j<64;j++) { - if (nextscale!=0) { - UINT delta=nalu.getSe(); - nextscale=(lastscale+delta+256)%256; - } - lastscale=(nextscale==0)?lastscale:nextscale; - } - } - } - } - } - } - int chromunitx=1; - int chromunity=1; - switch (chroma) { - case 0: - chromunitx=chromunity=1; break; - case 1: - chromunitx=chromunity=2; break; - case 2: - chromunitx=2;chromunity=1; break; - case 3: - chromunitx=chromunity=1; break; - }; - - nalu.getUe(); //log2framenum - UINT temp=nalu.getUe(); - if (temp==0) //pict order - nalu.getUe(); - else if (temp==1) { - nalu.getBits(1); - nalu.getSe(); - nalu.getSe(); - UINT temp2=nalu.getUe(); - for (UINT i=0;i1) { - if (!h264) { - interlaced=!(packet[pos+1] & 0x08); //really simple - // if more than full hd is coming we need to add additional parsers here - } else { - /* NALUUnit nalu(packet.getData()+posext,packet.getSize()-posext); - while (!nalu.isEonalu()) { - unsigned int payloadtype=0; - unsigned int payloadadd=0xFF; - while (payloadadd==0xFF && !nalu.isEonalu()) { - payloadadd=nalu.getBits(8); - payloadtype+=payloadadd; - } - unsigned int payloadsize=0; - payloadadd=0xff; - while (payloadadd==0xFF && !nalu.isEonalu()) { - payloadadd=nalu.getBits(8); - payloadsize+=payloadadd; - } - switch (payloadtype) { - case 1: { // picture timing SEI - - } break; - default: { - while (payloadsize) { // not handled skip - nalu.getBits(8); - payloadsize--; - } - } break; - } - - - - }*/ - - - } - } - - if (vid_seeking) - { - vid_seeking = 0; - video_pts_seek = video_pts; - LogNT::getInstance()->debug(TAG, "Entering audio sync: Video PTS = {}", video_pts); - LogNT::getInstance()->debug(TAG, "Entering audio sync: Audio PTS = {}", audio_pts); - } - return; - } - } -} - -UINT Demuxer::stripAudio(UCHAR* buf, UINT len) -{ - UINT read_pos = 0, write_pos = 0; - UINT pattern, packet_length; - if (len < 4) return 0; - pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); - while (read_pos + 7 <= len) - { - pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3]; - if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX)) - read_pos++; - else - { - packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6; - if (read_pos + packet_length > len) - read_pos = len; - else - { - if (read_pos != write_pos) - memmove(buf+write_pos, buf+read_pos, packet_length); - read_pos += packet_length; - write_pos += packet_length; - pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8) - | (buf[read_pos+2]); - } - } - } - return write_pos; -} - -void Demuxer::changeTimes(UCHAR* buf, UINT len,UINT playtime) -{ - UINT pattern, packet_length; - UINT read_pos = 0; - if (len < 4) return; - pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); - while (read_pos + 7 <= len) - { - pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3]; - if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX)) - read_pos++; - else - { - packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6; - // ok we have a packet figure out if pts and dts are present and replace them - if (read_pos + 19 > len) return; - ULLONG new_ts=playtime*90; //play time is on ms so multiply it by 90 - if (buf[read_pos+7] & 0x80) { // pts is here, replace it - buf[read_pos+9]=0x21 | (( new_ts>>29)& 0xde ); - buf[read_pos+10]=0x00 |(( new_ts>>22)& 0xff ); - buf[read_pos+11]=0x01 | (( new_ts>>14)& 0xfe ); - buf[read_pos+12]=0x00 | (( new_ts>>7)& 0xff ); - buf[read_pos+13]=0x01 | (( new_ts<<1)& 0xfe ); - } - - if (buf[read_pos+7] & 0x40) { // pts is here, replace it - buf[read_pos+14]=0x21 | (( new_ts>>29)& 0xde ); - buf[read_pos+15]=0x00 | (( new_ts>>22)& 0xff ); - buf[read_pos+16]=0x01 | (( new_ts>>14)& 0xfe ); - buf[read_pos+17]=0x00 | (( new_ts>>7)& 0xff ); - buf[read_pos+18]=0x01 | (( new_ts<<1)& 0xfe ); - } - read_pos += packet_length; - pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8) - | (buf[read_pos+2]); - } - } - -} - -bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264) -{ - UINT pos = 3; - UINT pattern; - ish264=false; - if (len < 4) return false; - pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); - while (pos < len) - { - pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++]; - if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX)) - return true; - } - return false; -} - -bool* Demuxer::getmpAudioChannels() -{ - return avail_mpaudchan; -} - -bool* Demuxer::getac3AudioChannels() -{ - return avail_ac3audchan; -} - -bool* Demuxer::getSubtitleChannels() -{ - return avail_dvbsubtitlechan; -} - -int Demuxer::getselSubtitleChannel() -{ - return subtitle_current; -} - -int Demuxer::getselAudioChannel() -{ - return audio_current; -} - - diff --git a/demuxer.h b/demuxer.h deleted file mode 100644 index b7c9771..0000000 --- a/demuxer.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - Copyright 2005-2008 Mark Calderbank - Copyright 2007 Marten Richter (AC3 support) - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP. If not, see . -*/ - -/* - -Thanks go to Jon Gettler of the MVPMC project and Stephen Rice for -the demuxer in mvpmc. It was used in the creation of this demuxer; -however, no code was copied verbatim. - -*/ - -#ifndef DEMUXER_H -#define DEMUXER_H - -#include "stream.h" -#include "defines.h" - -class DVBSubtitles; -class Callback; -class DrainTarget; - -struct PictCountInfo -{ - bool hassps; - bool hasaccessunit; - int log2_max_frame_num; - int frame_mbs_only_flag; - int separate_color_plane_flag; -}; - -class PESPacket -{ - public: - PESPacket(); - PESPacket(const PESPacket& packet); - PESPacket& operator=(const PESPacket& packet); - ~PESPacket(); - void init(UCHAR type, UCHAR sub = 0); - void truncate(); - int write(const UCHAR* buf, int len); - - UCHAR operator[] (UINT index) const; - // return data[index] if in bounds, else 0 - // so no proper error condition but never mind for now - const UCHAR* getData() const { return data; } - UINT getLength() const { return length; } - UINT getSize() const { return size; } - UCHAR getPacketType() const { return packetType; } - void setSubstream(UCHAR s) { substream = s; } - UCHAR getSubstream() const { return substream; } - ULLONG getPTS() const; - bool hasPTS() const { return (getPTS() != PTS_INVALID); } - - UINT findPictureHeader(bool h264) const; - UINT findSeqHeader(bool h264) const; - UINT findSeqExtHeader(bool h264) const; - UINT countPictureHeaders(bool h264, struct PictCountInfo& pinfo) const; - static const ULLONG PTS_INVALID = (1LL << 33); - - - - protected: - void copyFrom(const PESPacket& packet); - UCHAR * data; - UINT length, size; - UINT data_size; - UCHAR packetType; - UCHAR substream; - UINT mutable seq_header; // 0 = no, 1 = unknown, else = header offset -}; - -class Demuxer -{ - public: - Demuxer(); - virtual ~Demuxer(); - static Demuxer* getInstance(); - int init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, - DrainTarget* teletext, - ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, double fps=25., - DVBSubtitles* tsubtitles=NULL); - virtual void reset(); - virtual void flush(); - void flushAudio(); - void seek(); - void setVideoStream(int id); - //TODO HANS next virtual necessary? - //virtual void setAudioStream(int id); - void setAudioStream(int id); - void setTeletextStream(int id); - void setDVBSubtitleStream(int id); - bool writeAudio(bool * dataavail=NULL); - bool writeVideo(bool * dataavail=NULL); - bool writeTeletext(bool * dataavail=NULL); - - virtual int scan(UCHAR* buf, int len) = 0; - virtual int findPTS(UCHAR* buf, int len, ULLONG* dest) = 0; - virtual int put(UCHAR* buf, int len) = 0; - virtual void setFrameNum(ULONG /* frame */) {} - virtual void setPacketNum(ULONG /* packet */) {} - virtual ULONG getFrameNumFromPTS(ULLONG /* pts */) { return 0; } - virtual ULONG getPacketNum() {return 0;} - - bool* getmpAudioChannels(); //Maybe virtual ? - bool* getac3AudioChannels(); //Maybe virtual ? - bool* getSubtitleChannels(); - int getselAudioChannel(); - int getselSubtitleChannel(); - bool ish264() {return h264;} - void seth264(bool newh264){h264=newh264;} - - int getHorizontalSize() { return horizontal_size; } - int getVerticalSize() { return vertical_size; } - UCHAR getAspectRatio(int *tparx,int *tpary) { - *tparx=parx; *tpary=pary;return aspect_ratio; } - int getFrameRate() { return frame_rate; } - int getBitRate() { return bit_rate; } - bool getInterlaced() { return interlaced;} - ULLONG getVideoPTS() { return video_pts; } - ULLONG getAudioPTS() { return audio_pts; } - - enum AspectRatio : UCHAR - { - ASPECT_1_1 = 1, - ASPECT_4_3 = 2, - ASPECT_16_9 = 3, - ASPECT_221 = 4, - }; - - // Remove all data from a buffer apart from video PES packets. - // Returns the length of the reduced data. - // removed *static function*, due to DemuxerTS - virtual UINT stripAudio(UCHAR* buf, UINT len); - void changeTimes(UCHAR* buf, UINT len,UINT playtime); - - // Scan a buffer to see if video packets are present. - // Returns true if video exists; false if not. - // removed *static function* for h264 detection - static bool scanForVideo(UCHAR* buf, UINT len, bool &ish264); - - enum PESTYPE - { - PESTYPE_PRIVATE_1 = 0xBD, - - PESTYPE_AUD0 = 0xC0, - PESTYPE_AUD1, PESTYPE_AUD2, PESTYPE_AUD3, PESTYPE_AUD4, - PESTYPE_AUD5, PESTYPE_AUD6, PESTYPE_AUD7, PESTYPE_AUD8, - PESTYPE_AUD9, PESTYPE_AUD10, PESTYPE_AUD11, PESTYPE_AUD12, - PESTYPE_AUD13, PESTYPE_AUD14, PESTYPE_AUD15, PESTYPE_AUD16, - PESTYPE_AUD17, PESTYPE_AUD18, PESTYPE_AUD19, PESTYPE_AUD20, - PESTYPE_AUD21, PESTYPE_AUD22, PESTYPE_AUD23, PESTYPE_AUD24, - PESTYPE_AUD25, PESTYPE_AUD26, PESTYPE_AUD27, PESTYPE_AUD28, - PESTYPE_AUD29, PESTYPE_AUD30, PESTYPE_AUD31, - PESTYPE_AUDMAX = PESTYPE_AUD31, - - PESTYPE_VID0 = 0xE0, - PESTYPE_VID1, PESTYPE_VID2, PESTYPE_VID3, PESTYPE_VID4, - PESTYPE_VID5, PESTYPE_VID6, PESTYPE_VID7, PESTYPE_VID8, - PESTYPE_VID9, PESTYPE_VID10, PESTYPE_VID11, PESTYPE_VID12, - PESTYPE_VID13, PESTYPE_VID14, PESTYPE_VID15, - PESTYPE_VIDMAX = PESTYPE_VID15 - }; - enum PESTYPE_SUBSTREAM - { - PESTYPE_SUBSTREAM_TELETEXT0 = 0x10, - PESTYPE_SUBSTREAM_TELETEXT1,PESTYPE_SUBSTREAM_TELETEXT2, PESTYPE_SUBSTREAM_TELETEXT3, - PESTYPE_SUBSTREAM_TELETEXT4,PESTYPE_SUBSTREAM_TELETEXT5,PESTYPE_SUBSTREAM_TELETEXT6, - PESTYPE_SUBSTREAM_TELETEXT7, PESTYPE_SUBSTREAM_TELETEXT8, PESTYPE_SUBSTREAM_TELETEXT9, - PESTYPE_SUBSTREAM_TELETEXT10,PESTYPE_SUBSTREAM_TELETEXT11,PESTYPE_SUBSTREAM_TELETEXT12, - PESTYPE_SUBSTREAM_TELETEXT13,PESTYPE_SUBSTREAM_TELETEXT14,PESTYPE_SUBSTREAM_TELETEXT15, - PESTYPE_SUBSTREAM_TELETEXTMAX=PESTYPE_SUBSTREAM_TELETEXT15, - PESTYPE_SUBSTREAM_DVBSUBTITLE0=0x20, - PESTYPE_SUBSTREAM_DVBSUBTITLE1,PESTYPE_SUBSTREAM_DVBSUBTITLE2,PESTYPE_SUBSTREAM_DVBSUBTITLE3, - PESTYPE_SUBSTREAM_DVBSUBTITLE4,PESTYPE_SUBSTREAM_DVBSUBTITLE5,PESTYPE_SUBSTREAM_DVBSUBTITLE6, - PESTYPE_SUBSTREAM_DVBSUBTITLE7, - PESTYPE_SUBSTREAM_DVBSUBTITLEMAX=PESTYPE_SUBSTREAM_DVBSUBTITLE7, - PESTYPE_SUBSTREAM_AC30 = 0x80, - PESTYPE_SUBSTREAM_AC31,PESTYPE_SUBSTREAM_AC32, PESTYPE_SUBSTREAM_AC33, - PESTYPE_SUBSTREAM_AC34,PESTYPE_SUBSTREAM_AC35,PESTYPE_SUBSTREAM_AC36, - PESTYPE_SUBSTREAM_AC37, - PESTYPE_SUBSTREAM_AC3MAX = PESTYPE_SUBSTREAM_AC37 - }; - - protected: - // Operations on PES packets - bool submitPacket(PESPacket&); - void parsePacketDetails(PESPacket&); - - // General demuxer objects and status indicators - static Demuxer* instance; - Stream videostream; - Stream audiostream; - DVBSubtitles* subtitles; - Stream teletextstream; - int shutdown(); - bool initted; - bool vid_seeking; - bool aud_seeking; - bool h264; - int video_current, audio_current, teletext_current, subtitle_current; - int astreamtype; - bool livetv; - - // Video stream information - void setAspectRatio(enum AspectRatio, int taspectx, int taspecty); - int parx; - int pary; - Callback* callback; - - int horizontal_size; - int vertical_size; - bool interlaced; - int profile; - enum AspectRatio aspect_ratio; - int arcnt; - int frame_rate; - int bit_rate; - ULLONG video_pts; - ULLONG video_pts_seek; - ULLONG audio_pts; - ULLONG teletext_pts; - bool isteletextdecoded; - - - unsigned int packetnum; - - // Constants - static const int FrameRates[9]; - - double fps; - - bool ispre_1_3_19; - bool avail_mpaudchan[PESTYPE_AUDMAX-PESTYPE_AUD0+1]; - bool avail_ac3audchan[PESTYPE_SUBSTREAM_AC3MAX-PESTYPE_SUBSTREAM_AC30+1]; - bool avail_dvbsubtitlechan[PESTYPE_SUBSTREAM_DVBSUBTITLEMAX-PESTYPE_SUBSTREAM_DVBSUBTITLE0+1]; -}; - -#endif diff --git a/demuxeraudio.cc b/demuxeraudio.cc deleted file mode 100644 index ad6f391..0000000 --- a/demuxeraudio.cc +++ /dev/null @@ -1,1248 +0,0 @@ -/* - Copyright 2006 Mark Calderbank, Andreas Vogel - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "demuxeraudio.h" -#include "audio.h" -#include "i18n.h" -#include "oldlog.h" - -#define HDRBYTE1 0xff -#define HDRBYTE2 0xe0 -#define HDRBYTE2MASK 0xe0 - - - -class PacketBuffer { - - public: - PacketBuffer(Stream *as,UCHAR strtype) { - log=Log::getInstance(); - audio=as; - streamtype=strtype; - newStream(); - } - //just handle the data (do not deal with headers) - int putInternal(UCHAR* buf,int len,unsigned int &packetnum); - void reset(){ - partPacket=0; - bytesWritten=0; - framelen=DemuxerAudio::PACKET_SIZE; - } - void newStream() { - reset(); - numpackets=0; - numbytes=0; - skipfactor=0; - numskip=0; - } - bool bufferFull() { - return (partPacket>=framelen); - } - //can we write a new packet? - bool bufferEmpty() { - return partPacket==0; - } - //only set this, if buffer empty - //otherwise ignored! - bool setFramelen(int len) { - if (! bufferEmpty() ) return false; - if (len > (int)DemuxerAudio::PACKET_SIZE) return false; - framelen=len; - return true; - } - //how much bytes do we need to fill the packet? - int bytesMissing() { - return framelen-partPacket; - } - int getFramelen() { - return framelen; - } - void setSkipFactor(int factor) { - skipfactor=factor; - numskip=0; - } - private: - void packetWritten() { - numbytes+=framelen; - //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written packet %ld l=%d, bytes %ld",numpackets,framelen,numbytes); - numpackets++; - reset(); - } - bool doSkip(); - UCHAR store[DemuxerAudio::PACKET_SIZE]; // Storage for partial packets - int partPacket; // Length of partial packet stored from previous put() - int bytesWritten; //if they are !=0 and != framelength the stream is full... - int framelen; - Log * log; - Stream * audio; - UCHAR streamtype; - //global counters - ULONG numpackets; - ULONG numbytes; - int skipfactor; - int numskip; -}; - - -DemuxerAudio::DemuxerAudio(int p_vID, int p_aID) -{ - inSync=false; - isStarting=true; - log=Log::getInstance(); - readHeaders=0; - streamtype=Audio::MP3; - buffer=new PacketBuffer(&audiostream,streamtype); -// buffer=new PacketBuffer(&teststream,streamtype); - globalBytesWritten=0; - packetnum=0; - id3=NULL; - info=NULL; - vbr=NULL; - reset(); -} - -DemuxerAudio::~DemuxerAudio() { - delete buffer; - if(info) delete info; - if(id3) delete id3; - if (vbr) delete vbr; -} - -void DemuxerAudio::flush() -{ - Demuxer::flushAudio(); - buffer->newStream(); - tmpFill=0; -} - -void DemuxerAudio::reset() { - buffer->newStream(); - tmpFill=0; - readHeaders=0; - packetnum=0; - outOfSync=0; - globalBytesWritten=0; - if (id3) delete id3; - id3=NULL; - if (info) delete info; - info=NULL; - if (vbr) delete vbr; - vbr=NULL; - inSync=false; - hasHdrInfo=false; - hasVBRInfo=false; - isStarting=true; - hdrBitrate=128000; - hdrSamplingRate=44100; - avrBitrate=0; - hdrFramelen=0; - isStarting=true; -} - -int DemuxerAudio::scan(UCHAR *buf, int len) -{ - //no differend pids here - return 0; -} - -void DemuxerAudio::setVID(int p_vID) -{ -} - -void DemuxerAudio::setAID(int p_aID,int type) -{ -} - -static const char * id3_1_genre[] = { - "Blueshhh", - "Classic Rock", - "Country", - "Dance", - "Disco", - "Funk", - "Grunge", - "Hip-Hop", - "Jazz", - "Metal", - "New Age", - "Oldies", - "Other", - "Pop", - "R&B", - "Rap", - "Reggae", - "Rock", - "Techno", - "Industrial", - "Alternative", - "Ska", - "Death Metal", - "Pranks", - "Soundtrack", - "Euro-Techno", - "Ambient", - "Trip-Hop", - "Vocal", - "Jazz+Funk", - "Fusion", - "Trance", - "Classical", - "Instrumental", - "Acid", - "House", - "Game", - "Sound Clip", - "Gospel", - "Noise", - "AlternRock", - "Bass", - "Soul", - "Punk", - "Space", - "Meditative", - "Instrumental Pop", - "Instrumental Rock", - "Ethnic", - "Gothic", - "Darkwave", - "Techno-Industrial", - "Electronic", - "Pop-Folk", - "Eurodance", - "Dream", - "Southern Rock", - "Comedy", - "Cult", - "Gangsta", - "Top 40", - "Christian Rap", - "Pop/Funk", - "Jungle", - "Native American", - "Cabaret", - "New Wave", - "Psychadelic", - "Rave", - "Showtunes", - "Trailer", - "Lo-Fi", - "Tribal", - "Acid Punk", - "Acid Jazz", - "Polka", - "Retro", - "Musical", - "Rock & Roll", - "Hard Rock" -}; - - - -static int bitrateTable[16][5]={ -/* L1,L2,L3,2L1,2L2 */ -/*0000*/ {-1,-1,-1,-1,-1}, -/*0001*/ {32,32,32,32,8}, -/*0010*/ {64,48,40,48,16}, -/*0011*/ {96,56,48,56,24}, -/*0100*/ {128,64,56,64,32}, -/*0101*/ {160,80,64,80,40}, -/*0110*/ {192,96,80,96,48}, -/*0111*/ {224,112,96,112,56}, -/*1000*/ {256,128,112,128,64}, -/*1001*/ {288,160,128,144,80}, -/*1010*/ {320,192,160,160,96}, -/*1011*/ {352,224,192,176,112}, -/*1100*/ {384,256,224,192,128}, -/*1101*/ {416,320,256,224,144}, -/*1110*/ {448,384,320,256,160}, -/*1111*/ {-1,-1,-1,-1,-1} }; - -static int samplingRateTable[4][3]={ -/*00*/ {44100,22050,11025}, -/*01*/ {48000,24000,12000}, -/*10*/ {32000,16000,8000}, -/*11*/ {-1,-1,-1}}; - -//max 7 char! -static const char * mpegString(UCHAR code) { - switch(code) { - case 0: - return "MPEG2.5"; - case 1: - return "RESERV"; - case 2: - return "MPEG 2"; - case 3: - return "MPEG 1"; - } - return "UNKNOWN"; -} - -static const char * layerString(UCHAR code) { - switch(code) { - case 0: - return "Layer reserved"; - case 1: - return "Layer III"; - case 2: - return "Layer II"; - case 3: - return "Layer I"; - } - return "Layer UNKNOWN"; -} -/** - * parse an id3 Header - * provided by Brian Walton - * @returns -1 of nothing found - */ - -int DemuxerAudio::id3_2_3_FrameParse(unsigned char buf[], id3_frame *frame) -{ - if (buf[0] < 0x20 || buf[1] < 0x20 || buf [2] < 0x20 ) return -1; - frame->size = (buf[4] & 0x7F) << 21 | (buf[5] & 0x7F) << 14 | (buf[6] & 0x7F) << 7 | (buf[7] & 0x7F); - if (frame->size == 0) return -1; - //TODO. clearify flags against: - //http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b - frame->flags.tagAlterPreserv = (buf[8] & 0x80) >> 7; - frame->flags.filelterPreserv = (buf[8] & 0x40) >> 6; - frame->flags.readOnly = (buf[8] & 0x20) >> 5; - frame->flags.groupId = (buf[9] & 0x20) >> 5; - frame->flags.compression = (buf[9] & 0x80) >> 7; - frame->flags.encryption = (buf[9] & 0x40) >> 6; - frame->flags.unsync = 0; - frame->flags.dataLen = 0; - return 0; -} - - /** - * parse an id3 Header - * provided by Brian Walton - * @returns -1 of nothing found - */ - -int DemuxerAudio::id3_2_2_FrameParse(unsigned char buf[], id3_frame *frame) -{ - if (buf[0] < 0x20 || buf[1] < 0x20 || buf[2] < 0x20) return -1; - frame->size = (buf[3] & 0x7F) << 14 | (buf[4] & 0x7F) << 7 | (buf[5] & 0x7F); - if (frame->size == 0) return -1; - return 0; -} - - -//fill an id3tag from a frame payload -//http://id3.org/id3v2.3.0#head-697d09c50ed7fa96fb66c6b0a9d93585e2652b0b -//http://id3.org/id3v2-00 -static struct tagid { - const char * bytes; - int index; -} knownFrames[]= { - //ID3V2.3 - {"TIT2",1}, //title - {"TPE1",2}, //artist - {"TCON",3}, //genre - {"TRCK",6}, //track - {"TYER",4}, //year - {"TALB",5}, //album - {"TCOM",7}, //composer - {"COMM",8}, //comment - //Text encoding $xx - //Language $xx xx xx - //Short content descrip. $00 (00) - //The actual text - //ID3V2.0 - {"TT2",1 }, - {"TP1",2 }, - {"TCM",7 }, - {"TCO",3 }, //(genreNumber) - {"TAL",5 }, - {"TRK",6 }, - {"TYE",4 }, - {"COM",8 } -}; -#define NUMKNOWN (sizeof(knownFrames)/sizeof(knownFrames[0])) - -/*fill in infos - from an ID3 V2.x, V2.3 frame into the tags structure - frameData must point to the header - framelen is the len without header (10 Bytes for V23, 6 Bytes for v2x) - */ - -#define MAXLEN(tagtype) ((UINT)frameLentagtype)-1?(UINT)frameLen:sizeof(tag->tagtype)-1) -bool DemuxerAudio::fillId3Tag(id3_tag * tag,UCHAR * frameData, int frameLen, int dataOffset, bool v23) { - int tl=v23?4:3; - int tagIndex=-1; - if (tag == NULL) return false; - if (frameLen < 2) return false; - for (UINT i=0;i< NUMKNOWN;i++) { - if(strncmp((char *)frameData,knownFrames[i].bytes,tl) == 0) { - tagIndex=knownFrames[i].index; - break; - } - } - if (tagIndex < 0) return false; - UCHAR encoding=*(frameData+dataOffset); - dataOffset++; - frameLen--; - if (encoding != 0) { - log->log("DemuxerAudio",Log::DEBUG,"unknown encoding for tag %d, tagid %s",encoding, - knownFrames[tagIndex].bytes); - return false; - } - switch(tagIndex) { - case 1: //title - strncpy(tag->title,(char*)(frameData+dataOffset),MAXLEN(title)); - tag->title[MAXLEN(title)]=0; - break; - case 2: //artist - strncpy(tag->artist,(char*)(frameData+dataOffset),MAXLEN(artist)); - tag->artist[MAXLEN(artist)]=0; - break; - case 3: //genre - { - UCHAR * st=frameData+dataOffset; - int genre=0; - if (*st=='(') { - genre=atoi((const char *)(st+1)) && 31; - st=(UCHAR *)id3_1_genre[genre]; - } - strncpy(tag->genre,(char*)st,MAXLEN(genre)); - tag->genre[MAXLEN(genre)]=0; - break; - } - case 4: //year - strncpy(tag->year,(char *)(frameData+dataOffset),MAXLEN(year)); - tag->year[MAXLEN(year)]=0; - break; - case 5: //album - strncpy(tag->album,(char *)(frameData+dataOffset),MAXLEN(album)); - tag->album[MAXLEN(album)]=0; - break; - case 6: //track - strncpy(tag->track,(char *)(frameData+dataOffset),MAXLEN(track)); - tag->track[MAXLEN(track)]=0; - break; - case 7: //composer - strncpy(tag->composer,(char *)(frameData+dataOffset),MAXLEN(composer)); - tag->composer[MAXLEN(composer)]=0; - break; - case 8: //comment - strncpy(tag->comment,(char *)(frameData+dataOffset),MAXLEN(comment)); - tag->comment[MAXLEN(comment)]=0; - break; - default: - return false; - } - - return true; -} - -/** - * parse an id3 Header - * based on code provided by Brian Walton - * @returns -1 of nothing found - * otherwise the id3 info is filled - */ - -int DemuxerAudio::parseID3V2(UCHAR *data, int len) { - int debug=0; - UCHAR * start=data; - id3_header id3header; - id3_frame id3frame; - id3_tag * id3tag=NULL; - //len = read(fd, data, 10); - if (len < 10) { - delete id3tag; - return -1; - } - len-=10; - if(data[0]=='I' && data[1]=='D' && data[2]=='3') - { - id3tag=new id3_tag(); - id3header.major = data[3]; - id3header.minor = data[4]; - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 V2.%d.%d found\n", id3header.major, id3header.minor); - id3header.flags.unsynchronisation = (data[5] & 0x80)>>7; - id3header.flags.extended_header = (data[5] & 0x40)>>6; - id3header.flags.experimental = (data[5] & 0x20)>>5; - id3header.flags.footer = (data[5] & 0x10)>>4; - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Unsynchronisation flag: %d\n", id3header.flags.unsynchronisation); - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header flag: %d\n", id3header.flags.extended_header); - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Experimental indicator flag: %d\n", id3header.flags.experimental); - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Footer present flag: %d\n", id3header.flags.footer); - id3header.size = (data[6] & 0x7F) << 21 | (data[7] & 0x7F) << 14 | (data[8] & 0x7F) << 7 | (data[9] & 0x7F); - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"ID3 Size: %d\n", id3header.size); - data=start+10; - if (len <= id3header.size) { - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"header size to big %d, only %d bytes available\n",id3header.size,len); - delete id3tag; - return -1; - } - if (id3header.flags.extended_header) - { - int extended_hdr_hdr=4; //still to be discussed (id3.org...) - //read extended header size - if (len < extended_hdr_hdr) { - if (debug) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended header found but cannot read\n"); - delete id3tag; - return -1; - } - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"remaining %d chars after extended hdr hdr\n", len); - id3header.extended_header.size = (data[0] & 0x7F) << 21 | (data[1] & 0x7F) << 14 | (data[2] & 0x7F) << 7 | (data[3] & 0x7F); - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Extended header size: %d\n", id3header.extended_header.size); - if (len <= id3header.extended_header.size+extended_hdr_hdr) { - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"extended Header to big, only %d bytes available\n",len); - delete id3tag; - return -1; - } - //lseek(fd, id3header.extended_header.size - 6, SEEK_CUR); - data+=id3header.extended_header.size+extended_hdr_hdr; - len-=id3header.extended_header.size+extended_hdr_hdr; - } - //set the end of the header - UCHAR * eob=start+id3header.size+10; - bool readNext=true; - while (data < eob && readNext) - { - //skip over some padding - found this in lame MCDI tag... - if (*data == 0) { - data++; - continue; - } - readNext=false; - switch(id3header.major) - { - case 2: //ID3 V2.2.x - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.2 frame, %d : %c %c %c\n", data-start,*data,*(data+1),*(data+2)); - if (data + 6 >= eob) - { - break; - } - if (id3_2_2_FrameParse(data, &id3frame) < 0) - { - break; - } - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame size: %d\n", id3frame.size); - fillId3Tag(id3tag,data,id3frame.size,6,false); - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + 6 +1); - data+=6+id3frame.size; - readNext=true; - break; - case 3: //ID3 V2.3.x - { - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"version 2.3 frame, %d : %c %c %c %c\n", data-start, - *data,*(data+1),*(data+2),*(data+3)); - if (data + 10 >= eob) - { - break; - } - if (id3_2_3_FrameParse(data, &id3frame) <0) - { - break; - } - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame size: %d\n", id3frame.size); - int dataOffset=10; - if (id3frame.flags.groupId) - { - dataOffset++; - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame group: %d\n", data[dataOffset]); - } - if (id3frame.flags.compression) - { - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame compressed: %d\n", id3frame.flags.compression); - } - if (id3frame.flags.encryption) - { - dataOffset+=1; - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"Frame encryption method: %d\n", data[dataOffset]); - } - fillId3Tag(id3tag,data,id3frame.size-dataOffset+10,dataOffset,true); - if (debug != 0) log->log("DemuxerAudio::parseID3V2",Log::DEBUG,"frame payload: %s\n", data + dataOffset +1); - data+=10+id3frame.size; - readNext=true; - break; - } - default: - //don't support this version - delete id3tag; - return -1; - } - } - - data=eob; - //store the found tag - if (id3) delete id3; - id3=id3tag; - return data-start; - } - return -1; -} - -/** - * parse an id3v1 Header - * based on code provided by Brian Walton - * @returns -1 of nothing found - * otherwise the id3 info is filled - */ -#define MEMCPY(type,len,offset) {int type##max=sizeof(tag->type)-1type)-1:len;strncpy(tag->type,(char*)&data[offset],type##max);tag->type[type##max]=0;} - -int DemuxerAudio::parseID3V1(UCHAR *data, int len) { - int debug=1; - if (len < 128) return -1; - if(data[0]=='T' && data[1]=='A' && data[2]=='G') - { - id3_tag * tag=new id3_tag(); - if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1 tag found\n"); - MEMCPY(title,30,3); - MEMCPY(artist,30,33); - MEMCPY(album,30,63); - MEMCPY(year,4,93); - if (data[125]==0 && data[126]!=0) - { //ID3 V1.1 - if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.1 tag\n"); - MEMCPY(comment,29,97); - sprintf(tag->track, "%d", data[126]); - } else { - if (debug != 0)log->log("DemuxerAudio::parseID3V1",Log::DEBUG,"ID3 V1.0 tag\n"); - MEMCPY(comment,30,97); - } - if (data[127] < sizeof(id3_1_genre)/sizeof(id3_1_genre[0])) - { - sprintf(tag->genre, id3_1_genre[data[127]]); - } - if (id3) delete id3; - id3=tag; - return 0; - } - return -1; -} - -//infos from http://www.multiweb.cz/twoinches/MP3inside.htm -int DemuxerAudio::parseVBR(UCHAR *data, int len) { - UCHAR *hdr=findHeader(data,len); - //we expect the header exactly here - if (hdr != data) return -1; - const static char * VBRHDR="Xing"; - int vbridpos=36; - UCHAR mpgtype=(data[1] & 0x18)>>3; - UCHAR chmode=(data[2] & 0xc0) >> 6; - UCHAR layer=(data[2] & 0x06) >>1; - if ( mpgtype == 3 && chmode == 11) vbridpos=21; - if ( mpgtype != 3 && chmode != 11) vbridpos=21; - if ( mpgtype != 3 && chmode == 11) vbridpos=13; - //check for the header ID - if (vbridpos+(int)strlen(VBRHDR)+4 >= len) { - Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header %d",len); - return -1; - } - for (int i=4;ilog("DemuxerAudio::parseVBR",Log::DEBUG,"garbage when searching VBR header at pos %d",i); - return -1; - } - } - if ( strncmp((char *)&data[vbridpos],VBRHDR,strlen(VBRHDR)) != 0) { - Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"no VBR header at pos %d",vbridpos); - return -1; - } - int framedata=vbridpos+strlen(VBRHDR); - int expectedLen=0; - //OK we should now have a valid vbr header - bool hasFramenum=data[framedata+3] & 1; - bool hasBytes=data[framedata+3] & 0x2; - bool hasTOC=data[framedata+3] & 0x4; - expectedLen+=8; - if (hasTOC) expectedLen+=100; - if (framedata+expectedLen > len) { - Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"frame to short for VBR header data %d, expected %d", - len,framedata+expectedLen); - return -1; - } - if (!hasFramenum || ! hasBytes || ! hasTOC) { - //not usefull for us.. - Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"not all parts in VBR header - ignore"); - return -1; - } - framedata+=4; - if (vbr) delete vbr; - vbr=new vbrInfo(); - vbr->numFrames=data[framedata] << 24 | data[framedata+1]<<16| - data[framedata+2]<<8 |data[framedata+3]; - framedata+=4; - vbr->numBytes=data[framedata] << 24 | data[framedata+1]<<16| - data[framedata+2]<<8 |data[framedata+3]; - framedata+=4; - for (int ti=0;ti<100;ti++) { - vbr->table[ti]=data[framedata+ti]; - } - //compute file size in seconds - //should be (#of frames -1) *samplesPerFrame / sampleRate - //TODO: difference for Mono? - ULONG samplesPerFrame=384; //layer1 - if (layer != 3) samplesPerFrame=1152; - vbr->fileSeconds=(vbr->numFrames-1)*samplesPerFrame/hdrSamplingRate; - Log::getInstance()->log("DemuxerAudio::parseVBR",Log::DEBUG,"successfully read VBR %ldbytes, %ld frames, %ldsec", - vbr->numBytes,vbr->numFrames,vbr->fileSeconds); - return hdrFramelen; -} - - - - - - - -UCHAR * DemuxerAudio::findHeader(UCHAR *buf, int len, bool writeInfo) { - while (len >= 3) //assume hdr+crc - { - UCHAR pattern=*buf; - buf++; len--; - if (pattern != HDRBYTE1 ) continue; - if ((*buf & HDRBYTE2MASK) != HDRBYTE2) continue; - if (readHeader((buf-1),4,writeInfo) != 0) continue; - return buf-1; - } - return NULL; -} - - - -int DemuxerAudio::readHeader(UCHAR * hbuf,int len,bool writeInfo) { - int curFramelen=0; - int curBitrate=0; - int curSamplingRate=0; - if (*hbuf != HDRBYTE1) return -1; - hbuf++; - if ((*hbuf & HDRBYTE2MASK) != HDRBYTE2) return -1; - UCHAR mpgtype=(*hbuf & 0x18)>>3; - if (mpgtype == 1) { - log->log("DemuxerAudio",Log::DEBUG,"header invalid mpgtype %s %i %i %i", - mpegString(mpgtype),*hbuf,*(hbuf+1),*(hbuf+2)); - return 1; - } - UCHAR layer=(*hbuf & 0x06) >>1; - //bool hasCRC=!(*hbuf & 1); - hbuf++; - UCHAR bitrateCode=(*hbuf & 0xf0) >>4; - UCHAR samplingCode=(*hbuf & 0x0c) >> 2; - bool padding=*hbuf & 0x02; - hbuf++; - //0 Stereo, 1 JointStereo, 2 Dual, 3 Mono - UCHAR chmode=(*hbuf & 0xc0) >> 6; - //UCHAR extension=(*hbuf & 0x30) >> 4; - - //layercode: 1-L3, 2-L2, 3-L1 - //columns 0,1,2 for MPEG1 - UCHAR bitrateColumn=3-layer; - if (bitrateColumn > 2) { - log->log("DemuxerAudio",Log::DEBUG,"header invalid layer %s %i %i %i", - layerString(layer),*(hbuf-2),*(hbuf-1),*hbuf); - return 1; - } - if (mpgtype != 3) bitrateColumn+=3; - if (bitrateColumn>4) bitrateColumn=4; - curBitrate=1000*bitrateTable[bitrateCode][bitrateColumn]; - UCHAR sampleRateColumn=0; - if (mpgtype == 10) sampleRateColumn=1; - if (mpgtype == 0) sampleRateColumn=2; - curSamplingRate=samplingRateTable[samplingCode][sampleRateColumn]; - if (curSamplingRate < 0 || curBitrate < 0) { - log->log("DemuxerAudio",Log::DEBUG,"header invalid rates br=%d sr=%d %i %i %i", - curBitrate,curSamplingRate,*(hbuf-2),*(hbuf-1),*hbuf); - return 1; - } - int padbytes=0; - if (padding) { - if (layer == 3) padbytes=4; - else padbytes=1; - } - if (layer == 3) { - //Layer 1 - //FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4 - curFramelen=(12*curBitrate/curSamplingRate+padbytes) * 4; - } - else { - //Layer 2/3 - //FrameLengthInBytes = 144 * BitRate / SampleRate + Padding - curFramelen=144*curBitrate/curSamplingRate+padbytes; - } - //the header itself - if (curFramelen < 32) { - log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d-invalid %i %i %i", - readHeaders,mpegString(mpgtype),layerString(layer), - curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf); - return 1; - } - if (writeInfo || isStarting){ - log->log("DemuxerAudio",Log::DEBUG,"read header %ld mpgv=%s lc=%s br=%d sr=%d, fl=%d %i %i %i", - readHeaders,mpegString(mpgtype),layerString(layer), - curBitrate,curSamplingRate,curFramelen,*(hbuf-2),*(hbuf-1),*hbuf); - if (info) delete info; - info=new mpegInfo(); - strcpy(info->mpegVersion,mpegString(mpgtype)); - info->mpegLayer=4-layer; - info->bitRate=curBitrate; - info->avrBitrate=curBitrate; - info->sampleRate=curSamplingRate; - const char *chmodStr=tr("Stereo"); - switch (chmode) { - case 1: chmodStr=tr("JointStereo");break; - case 2: chmodStr=tr("Dual");break; - case 3: chmodStr=tr("Mono");break; - } - SNPRINTF(info->info,sizeof(info->info)-1,"%s",chmodStr); - } - if (isStarting) avrBitrate=curBitrate; - isStarting=false; - readHeaders++; - //moving average F=0.005 - avrBitrate=avrBitrate+((5*(curBitrate-avrBitrate))/1024); - hdrBitrate=curBitrate; - hdrFramelen=curFramelen; - hdrSamplingRate=curSamplingRate; - hasHdrInfo=true; - return 0; -} - -int DemuxerAudio::findPTS(UCHAR* buf, int len, ULLONG* dest) -{ - //we have no PTS number ... - *dest=0; - return (findHeader(buf,len) != NULL)?1:0; -} - -bool PacketBuffer::doSkip() { - if (!bufferFull()) return false; - if (skipfactor == 0) return false; - numskip++; - if (numskip >= skipfactor) { - //sent at least always 2 packets - if (numskip > skipfactor) numskip=0; - return false; - } - packetWritten(); - return true; -} - -// just handle the real stream without dealing with the header -int PacketBuffer::putInternal(UCHAR * wbuf, int len,unsigned int &packetnum) -{ - /* Important, the type passed to stream must be a mediapacket type as defined in - Draintarget.h and not the device setting of the mvp, so we have to translate it here, - in order to get it working on windows - --MR */ - UCHAR mptype=0; - switch (streamtype) { - case Audio::MPEG1_PES: //? - case Audio::MPEG2_PES: //Important, this must be a PES ! - mptype=MPTYPE_MPEG_AUDIO; break; - default: - case Audio::MP3: //this can be any Mpeg1 Audio not only layer 3 not packed into PES - mptype=MPTYPE_MPEG_AUDIO_LAYER3;break; - }; - if (bufferFull()) { -#ifndef WIN32 - if (doSkip()) return 0;//NoSkip on Windows -#endif - //we are still full - so try to write - int sent=audio->put(store+bytesWritten,framelen-bytesWritten,/*streamtype*/mptype,packetnum);packetnum++; - //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream (still full) pp=%d, framelen=%d, written=%d",sent,partPacket,framelen, bytesWritten ); - if (sent < (framelen - bytesWritten)) { - //packet still not written - bytesWritten+=sent; - return 0; - } - packetWritten(); - //let the demuxer come back with the rest - need to check header first - return 0; - } - if (partPacket+len >= framelen) { - //now we have at least a complete packet - int bytesConsumed=framelen-partPacket; - memcpy(store+partPacket,wbuf,bytesConsumed); - partPacket=framelen; - //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"stored packet %ld, length %d (last %d) for stream %p",numpackets,framelen,bytesConsumed,audio ); -#ifndef WIN32 //No Skip on Windows - if (doSkip()) return bytesConsumed; -#endif - int sent=audio->put(store,framelen,mptype,packetnum);packetnum++; - bytesWritten+=sent; - //log->log("DemuxerAudio::PacketBuffer",Log::DEBUG,"written %d bytes to stream",sent ); - if (bytesWritten < framelen) { - //still not completely written - return bytesConsumed; - } - packetWritten(); - //let the player come back... - return bytesConsumed; - } - //OK packet still not complete - if (len == 0) return 0; - int bytesConsumed=len; - memcpy(store+partPacket,wbuf,bytesConsumed); - partPacket+=bytesConsumed; - return bytesConsumed; -} - -/** - major entry for data from a player - the demuxer is either in the state headerSearch (packet written or - just at the beginning), writing garbage (inSync=false) or - handling data (none set) - A header is expected at the first byte after the previous packet - - otherwise we switch to garbage where we always search for a header - (but anyway provide the data to the underlying device - it's probably - more intelligent then we are... - We only loose a correct position display. - */ -int DemuxerAudio::put(UCHAR* wbuf, int len) -{ - //return audiostream.put(wbuf,len,streamtype); - int framelen=PACKET_SIZE; - UCHAR *hdr; - int bytesConsumed=0; - int oldBytes=0; - if (tmpFill != 0 || (buffer->bufferEmpty() && len < HDRLEN)) { - //OK we have to copy everything to the tmp buffer - int cp=(UINT)len<(PACKET_SIZE-tmpFill)?(UINT)len:(PACKET_SIZE-tmpFill); - memcpy(&tmpBuffer[tmpFill],wbuf,cp); - oldBytes=tmpFill; - tmpFill+=cp; - wbuf=tmpBuffer; - len=tmpFill; - //if there is no header here and our buffer - //is empty - just wait for the next header - if (len < HDRLEN && buffer->bufferEmpty()) { - log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten); - return cp; - } - } - while (bytesConsumed < len ) { - if (buffer->bufferFull()) { - //if this is the first part of the loop, try to write to the stream - if (bytesConsumed == 0) buffer->putInternal(wbuf,0,packetnum); - //if the buffer is full, no need to continue - if (buffer->bufferFull()) break; - } - //either we are in a packet (buffer != full && buffer != empty) - //or we are searching a header - if (buffer->bufferEmpty()) { - if (len-bytesConsumed < HDRLEN) { - // we cannot still search - if (tmpFill != 0) { - //we are already working at the buffer - break; - } - memcpy(tmpBuffer,wbuf,len-bytesConsumed); - tmpFill=len-bytesConsumed; - log->log("DemuxerAudio",Log::DEBUG,"len to small for header %d at bytes %ld",len,globalBytesWritten); - return len; - } - - int lastFramelen=hdrFramelen; - //if the header has been valid before and we are searching - //it should be here - int maxsearch=((len-bytesConsumed) < (int)PACKET_SIZE)?len-bytesConsumed:(int)PACKET_SIZE; - hdr=findHeader(wbuf,maxsearch); - if (hdr != NULL) { - //log->log("DemuxerAudio",Log::DEBUG,"header found at offset %d",hdr-wbuf); - } - //hdr now points to the new header - if (hdr != wbuf) { - //still at least bytes before the header - inSync=false; - outOfSync++; - int garbageBytes=(hdr!=NULL)?(hdr-wbuf):maxsearch; - //we consider the garbage now as an own packet - //we can consume at most our buffer - //basically the buffer should be empty here (we are - //in header search - and we fill up each garbage - - int nframesize=garbageBytes; - if (nframesize > (int)PACKET_SIZE) { - nframesize=(int)PACKET_SIZE; - } - if (! buffer->bufferEmpty()) { - log->log("DemuxerAudio",Log::WARN,"buffer not empty when having garbage to store"); - //at the end no big problem, we only write the remaining bytes that we have... - } - else { - buffer->setFramelen(nframesize); - } - log->log("DemuxerAudio",Log::DEBUG,"garbage found at packet %ld (bytes %ld) of length %d, " - "framelen set to %d (last fl=%d)", - readHeaders,globalBytesWritten,garbageBytes,buffer->getFramelen(),lastFramelen); -#ifndef WIN32 - //hmm - we assume that he low level driver is more intelligent - //and give him the data "as is" - int written=buffer->putInternal(wbuf,garbageBytes,packetnum); - globalBytesWritten+=written; - bytesConsumed+=written; - if (written != garbageBytes || hdr == NULL ) { - break; - } -#else //DS is not intelligent - globalBytesWritten+=garbageBytes; - bytesConsumed+=garbageBytes; -#endif - //OK either all the "garbage" is written or - //we found the next header as expected - //continue with the next package - wbuf=hdr; - } - //we have to wait now until the buffer is - //free for the next package - if ( ! buffer->bufferEmpty()) return bytesConsumed; - //this is the place where we start a new packet - framelen=hdrFramelen; - if ( !buffer->setFramelen(framelen) ) { - log->log("DemuxerAudio",Log::DEBUG,"unable to set framelen should=%d, current=%d", - framelen,buffer->getFramelen()); - } - inSync=true; - } - //now we are surely within a packet - int written=buffer->putInternal(wbuf,len-bytesConsumed,packetnum); - //update the status - globalBytesWritten+=written; - wbuf+=written; - bytesConsumed+=written; - if (written == 0) { - //stream is full - break; - } - //OK - handle the rest - } - if (bytesConsumed >= oldBytes) { - //if we consumed more than the old bytes - OK the buffer - //can be thrown away - tmpFill=0; - return bytesConsumed-oldBytes; - } - else { - //only consumed bytes from the buffer - if (bytesConsumed == 0) { - //restore the buffer - tmpFill=oldBytes; - return 0; - } - //shift bytes in buffer - for (int i=0;iavrBitrate=avrBitrate; - info->bitRate=hdrBitrate; - return info; -} - -const DemuxerAudio::vbrInfo * DemuxerAudio::getVBRINfo() { - return vbr; -} - -int DemuxerAudio::checkStart(UCHAR *b, int len) { - UCHAR *start=b; - int id3len=parseID3V2(b,len); - if (id3len > 0) { - char * str=id3->toString(); - log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 %d bytes of %d",id3len,len); - log->log("DemuxerAudio",Log::DEBUG,"parseID3V2 found:%s",str); - delete str; - b+=id3len; - len-=id3len; - } - int vbrlen=parseVBR(b,len); - if (vbrlen > 0 ) { - hasVBRInfo=true; - b+=vbrlen; - len-=vbrlen; - } - UCHAR * hdr=findHeader(b,len,true); - if (hdr == NULL) return -1; - return hdr-start; -} - -int DemuxerAudio::checkID3(UCHAR *b, int len) { - if (len != 128) return -1; - int rt=parseID3V1(b,len); - if (rt >= 0) { - char * str=id3->toString(); - log->log("DemuxerAudio",Log::DEBUG,"parseID3V1 found:%s",str); - delete str; - } - return rt; -} - -bool DemuxerAudio::isSync() { - return inSync; -} - -UINT DemuxerAudio::getSyncErrors() { - return outOfSync; -} - -ULONG DemuxerAudio::getBytesPerSecond() -{ - ULONG bps=hdrBitrate; - if (! hasHdrInfo) return 0; - if (hdrBitrate != avrBitrate) { - //we seem to have vbr - if (hasVBRInfo) { - //vbr stuff TODO - bps=avrBitrate; - } - else { - //some guessing - bps=avrBitrate; - } - } - bps=bps/8; - return bps; -} - -ULONG DemuxerAudio::getSecondsFromLen(ULONG len) { - if (! hasHdrInfo) return 0; - if (vbr) { - //first find the index where we are between - //rough starting point: - ULONG idx=100*len/vbr->numBytes; - if (idx >= 100) idx=99; - ULONG idxPos=(vbr->table[idx]) * vbr->numBytes/256; - ULONG pbefore=idxPos; - ULONG pafter=idxPos; - //OK now we know whether we have to go up or down - if (idxPos > len) { - //down - while (idxPos > len && idx > 0) { - pafter=idxPos; - idx--; - idxPos=(vbr->table[idx]) * vbr->numBytes/256; - pbefore=idxPos; - } - //OK we are now before our postion - } - else { - //up - while (idxPos < len && idx < 100 ) { - pbefore=idxPos; - idx++; - idxPos=(vbr->table[idx]) * vbr->numBytes/256; - pafter=idxPos; - } - //after our position - if (idx > 0) idx --; - } - //idx is now the index before our position - //approximate between the 2 points - ULONG idxTime=idx * vbr->fileSeconds/100; - if (pafter == pbefore) return idxTime; - ULONG rt=idxTime+ (len-pbefore)* vbr->fileSeconds/(100 * (pafter-pbefore)) ; - if (rt > vbr -> fileSeconds) return vbr->fileSeconds; - if (rt < idxTime) return idxTime; - return rt; - } - else { - ULONG bps=getBytesPerSecond(); - if (bps == 0) return 0; - return len/bps; - } -} - -ULONG DemuxerAudio::positionFromSeconds(ULONG seconds) { - if (! hasHdrInfo) return 0; - if (vbr) { - ULONG idx=seconds*100/vbr->fileSeconds; - if (idx > 99) idx=99; - ULONG idxPos=vbr->table[idx] * vbr->numBytes/256; - ULONG idx2=idx; - if (idx < 99) idx2++; - ULONG nextPos=vbr->table[idx] * vbr->numBytes/256; - ULONG rt=idxPos+(nextPos-idxPos) * (seconds - idx * vbr->fileSeconds /256); - if (rt < idxPos) return idxPos; - if ( rt > vbr->numBytes) return vbr->numBytes; - return rt; - } - else { - ULONG bps=getBytesPerSecond(); - return bps*seconds; - } -} - -int id3_tag::stringlen(bool withTitle) const { - if (!withTitle) - return strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+ - strlen(track)+strlen(composer)+strlen(comment)+8+3+ - 90; //30 chars for each name... - else - return strlen(title)+strlen(artist)+strlen(genre)+strlen(year)+strlen(album)+ - strlen(track)+strlen(composer)+strlen(comment)+8+3+ - 120; //30 chars for each name... -} -//create a string out of the id3 tag info -//delete this string afterwards if you did not provide the buffer -char * id3_tag::toString(char *b, int len, bool withTitle) const { - const char *ta=tr("Artist"); -//char *tg=tr("Genre"); -//char *ty=tr("Year"); - const char *tx=tr("Album"); -//char *to=tr("Composer"); -//char *tc=tr("Comment"); - const char *tn=tr("Track"); - /* in the moment: - Title: - Artist: - Album: year - name - Track: - */ - if (b == NULL) { - len=stringlen(withTitle); - b=new char[len]; - } - const char * del=" - "; - if (strlen(year) == 0) del=""; - if (withTitle){ - const char *tt=tr("Title"); - SNPRINTF(b,len-1,"%s: %s\n%s: %s\n%s: %s%s%s\n%s: %s", - tt,title,ta,artist,tx,year,del,album,tn,track); - } - else { -SNPRINTF(b,len-1,"%s: %s\n%s: %s%s%s\n%s: %s", - ta,artist,tx,year,del,album,tn,track); - } - b[len-1]=0; - return b; -} - -void DemuxerAudio::setSkipFactor(int factor) { - Log::getInstance()->log("DemuxerAudio",Log::DEBUG,"set skipfactor %d\n",factor); - buffer->setSkipFactor(factor); -} - diff --git a/demuxeraudio.h b/demuxeraudio.h deleted file mode 100644 index 4bbb868..0000000 --- a/demuxeraudio.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - Copyright 2006 Mark Calderbank, Andreas Vogel - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef DEMUXERAUDIO_H -#define DEMUXERAUDIO_H - -#include "demuxer.h" -#include "defines.h" -#include "id3.h" - -class Log; -class PacketBuffer; - -class DemuxerAudio : public Demuxer -{ - public: - typedef struct { - char mpegVersion[8]; //MPEG1/2/2,5 - int mpegLayer; //1,2,3 - int bitRate; - int avrBitrate; - int sampleRate; - char info[20]; //channel mode,... - } mpegInfo; - - typedef struct { - ULONG numFrames; - ULONG numBytes; - ULONG fileSeconds; - UCHAR table[100]; - } vbrInfo; - DemuxerAudio(int p_vID = 0, int p_aID = 0); - virtual ~DemuxerAudio(); - virtual void flush(); - virtual void reset(); - virtual int scan(UCHAR* buf, int len); - virtual int findPTS(UCHAR* buf, int len, ULLONG* dest); - virtual void setVID(int p_vID); - virtual void setAID(int p_aID,int type); - virtual int put(UCHAR* buf, int len); - - //special functions for the audioplayer - bool isSync() ; - UINT getSyncErrors(); - - //set the skip factor - void setSkipFactor(int faktor); - - //how many bytes do we need at the file start - //ID3V2, VBR + some spare to detect a first header - static UINT headerBytes() { - return 4096; - } - //how many bytes do we need at the end - static UINT footerBytes() { - return 128; - } - //return a reference to an ID3 tag - //if not found (from checkStart or checkID3) - //NULL will be returned - const id3_tag * getId3Tag(); - const mpegInfo * getMpegInfo(); - const vbrInfo * getVBRINfo(); - - //check for a valid header at the beginning (and parse all we find) - //will return the offset in buffer where the first valid - //header was found (with potentially skipping ID3 and VBR) - //return -1 if nothing found - int checkStart(UCHAR * buffer, int len); - //check for ID3V1 (at the end) - //return 0 if found - int checkID3(UCHAR * buffer, int len); - - //return length if we can do this - //otherwise return 0 - ULONG getSecondsFromLen(ULONG len); - - //position within a file - //return 0 if we cannot - ULONG positionFromSeconds(ULONG seconds); - - //try to read the iD3 tag value (V2xx) and - //fill it into the ID3 store - bool fillId3Tag(id3_tag * tag,UCHAR * frameData, int frameLen, int dataOffset, bool v23); - - const static UINT PACKET_SIZE=4096; - private: - /*max size of a packet - see http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm - assumptions: max br 448kb/s, min sample 16k - L2/L3 FrameLengthInBytes = 144 * BitRate / SampleRate + Padding - L2/3 28*144+8 -> 4040 - L1 FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4 - L1 (336+32)*4 = 1472 - */ - Log * log; - - int readHeader(UCHAR* buf, int len, bool writeInfo=false); - - //info flags for the player - bool inSync; //set if we read a valid header - UINT outOfSync; //counts each invalid read headers - bool hasHdrInfo; //if we have been able to successfully - //parse the first header - bool hasVBRInfo; //we have VBR and the necessary info - //infos from header - int hdrFramelen; - int hdrBitrate; - int hdrSamplingRate; - //a little bit guessing for VBR - int avrBitrate; - - int streamtype; - bool isStarting; - ULONG readHeaders; - ULONG globalBytesWritten; - - - //search for the start of a header - //return NULL if none found - UCHAR * findHeader(UCHAR * buf, int len, bool writeInfo=false); - //we need a buffer to be able to read at least a complete header - const static int HDRLEN=4; - UCHAR tmpBuffer[PACKET_SIZE+HDRLEN]; - UINT tmpFill; - - //compute the bytes/second from the BR info - //return 0 if not there; - ULONG getBytesPerSecond(); - - //parse ID3V2 at the beginning - //set info if there - //return length of header, -1 if not found - int parseID3V2(UCHAR *data, int len); - int id3_2_3_FrameParse(unsigned char buf[], id3_frame *frame); - int id3_2_2_FrameParse(unsigned char buf[], id3_frame *frame); - - //parse ID3V1 at the end - //set info if there, return -1 otherwise - int parseID3V1(UCHAR *data, int len) ; - - //parse a VBR header and set VBR info - //input has to point to firts MPEG header in file - //potentially after ID3V2 - int parseVBR(UCHAR *data, int len); - - - class PacketBuffer* buffer; - - id3_tag *id3; - mpegInfo *info; - vbrInfo *vbr; - - unsigned int packetnum; - - -}; - -#endif diff --git a/demuxermedia.cc b/demuxermedia.cc deleted file mode 100644 index 77a6a42..0000000 --- a/demuxermedia.cc +++ /dev/null @@ -1,348 +0,0 @@ -/* - Copyright 2005-2007 Mark Calderbank - - This file is part of VOMP. - - VOMP 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. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "demuxermedia.h" -#include "callback.h" - -#include "video.h" -#include "oldlog.h" - -#ifndef WIN32 -#include -#else -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#define __BYTE_ORDER __LITTLE_ENDIAN -#endif - -#define PTS_JUMP_MARGIN 10000 -#define PTS_ALLOWANCE 90000 - -// TODO: PTS class to handle wrapping arithmetic & comparisons? -static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2) -{ - // Assume pts1, pts2 < 2^33; calculate shortest distance between - ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1; - if (ret > (1LL<<32)) ret = (1LL<<33) - ret; - return ret; -} - -DemuxerMedia::DemuxerMedia() -{ - frameCounting = false; - packetCounting = false; -} - -void DemuxerMedia::reset() -{ - frameCounting = false; - packetCounting = false; - pts_map.clear(); - Demuxer::reset(); - firstPTS=0; - lastPTS=0; - currentPTS=0; - last_horizontal_size=-1; - last_vertical_size=-1; -} - -void DemuxerMedia::flush() -{ - state = 0; - submitting = false; - Demuxer::flush(); -} - -int DemuxerMedia::scan(UCHAR *buf, int len) -{ - int ret = 0; - int astate=0; //hdrbyte - - while ((len + astate)> 3) - { - switch (astate) { - case 0: //1st hdr byte - if (*buf != 0) break; - astate++; - break; - case 1: //2nd hdrbyte - if (*buf != 0) { - astate=0; - break; - } - astate++; - break; - case 2: //3rd header byte - if (*buf != 1) { - astate=0; - break; - } - astate++; - break; - case 3: //4th header byte - if ((*buf PESTYPE_AUDMAX) && *buf != PESTYPE_PRIVATE_1) { - astate=0; - break; - } - if (*buf != PESTYPE_PRIVATE_1) { - //found audio - ret=*buf; - return ret; - } - //AC3 - TODO - astate=0; - default: - astate=0; - break; - } - buf++; - len--; - } - return ret; -} - -int DemuxerMedia::findPTS(UCHAR* buf, int len, ULLONG* dest) -{ - // nobody uses this - // No PTS found. - return 0; -} - -void DemuxerMedia::setFrameNum(ULONG frame) -{ - frameCounting = true; - frameNumber = frame; - Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame); -} - -void DemuxerMedia::setPacketNum(ULONG npacket) -{ - packetCounting = true; - packetNumber = npacket; - Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket); -} - -int DemuxerMedia::put(UCHAR* buf, int len) -{ - int ret = 0; // return number of bytes consumed - if (submitting) - { - if (submitPacket(packet) == 0) // Still full! - return ret; - else - submitting = false; - } - - if (state > 0) // We are half way through a PES packet. - { - if (len >= state) // The remainder of the packet is available. - { - packet.write(buf, state); - buf += state; len -= state; ret += state; - state = 0; - parseVDRPacketDetails(); - if (submitPacket(packet) == 0) // Stream is full - { - submitting = true; - return ret; - } - } - else // Write what we have, then exit. - { - packet.write(buf, len); - state -= len; - return len; - } - } - - while (len > 0) - { - switch (state) - { - case 0: - case -1: - if (*buf == 0x00) state--; else state = 0; - buf++; len--; ret++; - break; - case -2: - if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0; - buf++; len--; ret++; - break; - case -3: - if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) || - (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) || - (*buf == PESTYPE_PRIVATE_1)) - { - packet.init(*buf); - state--; - } - else if (*buf == 0x00) - state = -1; - else - state = 0; - buf++; len--; ret++; - break; - case -4: - packetLength = ((UINT)*buf) << 8; - state--; - buf++; len--; ret++; - break; - case -5: - packetLength += *buf; - state--; - buf++; len--; ret++; - break; - } - - if (state == -6) // Packet header complete - { - if (len >= packetLength) // The entire packet is available. - { - packet.write(buf, packetLength); - buf += packetLength; len -= packetLength; ret += packetLength; - state = 0; - parseVDRPacketDetails(); - if (submitPacket(packet) == 0) // Stream is full - { - submitting = true; - return ret; - } - } - else // Write what we have. - { - packet.write(buf, len); - state = packetLength - len; - ret += len; - len = 0; - } - } - } - return ret; -} - -ULONG DemuxerMedia::getPacketNum() -{ - return packetNumber; -} - -void DemuxerMedia::parseVDRPacketDetails() -{ - parsePacketDetails(packet); - - if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 && - packet.getPacketType() <= PESTYPE_AUDMAX) - { - packetNumber++; - } - - if (frameCounting && packet.findPictureHeader(h264) && - packet.getPacketType() >= PESTYPE_VID0 && - packet.getPacketType() <= PESTYPE_VIDMAX) - { - ULLONG pts=packet.getPTS(); - if (packet.findSeqHeader(h264) > 1 && pts != PESPacket::PTS_INVALID) - { - if (firstPTS == 0) firstPTS=pts; - currentPTS=pts; - - } - } - if (packet.getPacketType() >= PESTYPE_VID0 && - packet.getPacketType() <= PESTYPE_VIDMAX && - packet.findSeqHeader(h264)) { - //check video size - if (horizontal_size != last_horizontal_size || - vertical_size != last_vertical_size) { - last_horizontal_size=horizontal_size; - last_vertical_size=vertical_size; - Log::getInstance()->log("Demux", Log::DEBUG,"signal size change, new x %d, y %d", - horizontal_size,vertical_size); - if (callback) callback->call(this); - } - } - -} - -//find a sequence header backward -//search for 00 00 01