summaryrefslogtreecommitdiff
path: root/liboutput
diff options
context:
space:
mode:
authorAndreas Brachold <vdr07@deltab.de>2005-07-19 15:09:05 +0000
committerAndreas Brachold <vdr07@deltab.de>2005-07-19 15:09:05 +0000
commitf897f2aa7055c493db6391c50c8d19da970078e8 (patch)
treed13a515b24c149d7da4e9828cc9e9c73d4916f00 /liboutput
downloadvdr-plugin-image-f897f2aa7055c493db6391c50c8d19da970078e8.tar.gz
vdr-plugin-image-f897f2aa7055c493db6391c50c8d19da970078e8.tar.bz2
Initial import with release 0.2.3
Diffstat (limited to 'liboutput')
-rw-r--r--liboutput/Makefile58
-rw-r--r--liboutput/encode.c369
-rw-r--r--liboutput/encode.h92
-rw-r--r--liboutput/stillimage-player.c61
-rw-r--r--liboutput/stillimage-player.h55
-rw-r--r--liboutput/stillimage.c210
-rw-r--r--liboutput/stillimage.h54
7 files changed, 899 insertions, 0 deletions
diff --git a/liboutput/Makefile b/liboutput/Makefile
new file mode 100644
index 0000000..acac360
--- /dev/null
+++ b/liboutput/Makefile
@@ -0,0 +1,58 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id$
+
+VDRDIR = ../../../..
+DVBDIR = ../../../../../DVB
+FFMDIR = ../../../../../ffmpeg
+
+### The C++ compiler and options:
+
+CXX ?= g++
+CXXFLAGS ?= -O0 -g -Wall -Woverloaded-virtual
+
+-include $(VDRDIR)/Make.config
+
+### The directory environment:
+
+
+INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
+
+DEFINES += -D_GNU_SOURCE
+
+LIBS +=
+
+ifdef FFMPEG_STATIC
+ INCLUDES += -I$(FFMDIR)
+ DEFINES += -DHAVE_FFMPEG_STATIC
+endif
+
+### The object files (add further files here):
+
+OBJS = encode.o stillimage.o stillimage-player.o
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: liboutput.a
+
+liboutput.a : $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+# $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -o $@
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.a *.so *.tgz core* *~
diff --git a/liboutput/encode.c b/liboutput/encode.c
new file mode 100644
index 0000000..351e30f
--- /dev/null
+++ b/liboutput/encode.c
@@ -0,0 +1,369 @@
+/***************************************************************************
+ * encode.c
+ *
+ * (C) Copyright 2004 Andreas Brachold <vdr04-at-deltab.de>
+ * Created: Thu Aug 5 2004
+ *
+ ****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef HAVE_FFMPEG_STATIC
+#include <dlfcn.h>
+#endif
+
+#include "encode.h"
+#include <vdr/device.h>
+#include <vdr/tools.h>
+
+typedef void (*f_avcodec_init)(void);
+typedef void (*f_avcodec_register_all)(void);
+typedef AVCodec *(*f_avcodec_find_encoder)(enum CodecID id);
+typedef AVCodecContext *(*f_avcodec_alloc_context)(void);
+typedef AVFrame *(*f_avcodec_alloc_frame)(void);
+typedef int (*f_avcodec_open)(AVCodecContext *avctx, AVCodec *codec);
+typedef int (*f_avcodec_close)(AVCodecContext *avctx);
+typedef int (*f_avcodec_encode_video)(AVCodecContext *avctx, uint8_t *buf, int buf_size,const AVFrame *pict);
+typedef int (*f_avpicture_fill)(AVPicture *picture, uint8_t *ptr, int pix_fmt, int width, int height);
+
+#if FFMPEG_VERSION_INT <= 0x000408
+typedef int (*f_img_convert)(AVPicture *dst, int dst_pix_fmt,AVPicture *src, int pix_fmt,int width, int height);
+#elif FFMPEG_VERSION_INT >= 0x000409
+typedef int (*f_img_convert)(AVPicture *dst, int dst_pix_fmt,const AVPicture *src, int pix_fmt,int width, int height);
+#else
+ #error "there is a unknow ffmpeg version or FFMPEG_VERSION_INT isnt defined"
+#endif
+
+#ifdef HAVE_FFMPEG_STATIC
+
+static f_avcodec_init fn_avcodec_init=avcodec_init;
+static f_avcodec_register_all fn_avcodec_register_all=avcodec_register_all;
+static f_avcodec_find_encoder fn_avcodec_find_encoder=avcodec_find_encoder;
+static f_avcodec_alloc_context fn_avcodec_alloc_context=avcodec_alloc_context;
+static f_avcodec_alloc_frame fn_avcodec_alloc_frame=avcodec_alloc_frame;
+static f_avcodec_open fn_avcodec_open=avcodec_open;
+static f_avcodec_close fn_avcodec_close=avcodec_close;
+static f_avcodec_encode_video fn_avcodec_encode_video=&avcodec_encode_video;
+static f_avpicture_fill fn_avpicture_fill=avpicture_fill;
+static f_img_convert fn_img_convert=img_convert;
+
+#else
+
+static f_avcodec_init fn_avcodec_init;
+static f_avcodec_register_all fn_avcodec_register_all;
+static f_avcodec_find_encoder fn_avcodec_find_encoder;
+static f_avcodec_alloc_context fn_avcodec_alloc_context;
+static f_avcodec_alloc_frame fn_avcodec_alloc_frame;
+static f_avcodec_open fn_avcodec_open;
+static f_avcodec_close fn_avcodec_close;
+static f_avcodec_encode_video fn_avcodec_encode_video;
+static f_avpicture_fill fn_avpicture_fill;
+static f_img_convert fn_img_convert;
+
+
+#define DLSYM(cast,sym,func) \
+ sym=(cast)dlsym(m_hLibAvcodec, func); \
+ bSuccess &= (sym != NULL); \
+ if(sym == NULL) \
+ esyslog("imageplugin: Link to function %s failed", func);
+
+void *cEncode::m_hLibAvcodec = NULL;
+
+
+/*******************************************************************************
+
+*/
+bool cEncode::InitLibAVCodec(void){
+
+ bool bSuccess=false;
+ // Let ld.so search the libary
+ const char* szLibary = "libavcodec.so";
+ m_hLibAvcodec=dlopen(szLibary, RTLD_LAZY);
+ if(!m_hLibAvcodec)
+ {
+ esyslog("imageplugin: Loading %s failed : %s", szLibary,dlerror());
+ }
+ /* map the lib's syms to our wrapper */
+ else {
+
+ bSuccess=true;
+ DLSYM(f_avcodec_init,fn_avcodec_init,"avcodec_init");
+ DLSYM(f_avcodec_init,fn_avcodec_register_all,"avcodec_register_all");
+ DLSYM(f_avcodec_find_encoder,fn_avcodec_find_encoder,"avcodec_find_encoder");
+ DLSYM(f_avcodec_alloc_context,fn_avcodec_alloc_context,"avcodec_alloc_context");
+ DLSYM(f_avcodec_alloc_frame,fn_avcodec_alloc_frame,"avcodec_alloc_frame");
+ DLSYM(f_avcodec_open,fn_avcodec_open,"avcodec_open");
+ DLSYM(f_avcodec_close,fn_avcodec_close,"avcodec_close");
+ DLSYM(f_avcodec_encode_video,fn_avcodec_encode_video,"avcodec_encode_video");
+ DLSYM(f_avpicture_fill,fn_avpicture_fill,"avpicture_fill");
+ DLSYM(f_img_convert,fn_img_convert,"img_convert");
+ }
+
+ return(bSuccess);
+}
+
+/*******************************************************************************
+
+*/
+void cEncode::CloseLibAVCodec(void){
+
+ if (m_hLibAvcodec)
+ dlclose(m_hLibAvcodec);
+ m_hLibAvcodec = NULL;
+}
+#endif
+
+/*******************************************************************************
+
+*/
+cEncode::cEncode()
+: m_pavCodec(NULL)
+, m_pImageFilled(NULL)
+, m_pImageYUV(NULL)
+, m_nFrames(4)
+, m_nData(0)
+, m_pMPEG(NULL)
+, m_pImageRGB(NULL)
+{
+ m_bLoaded = false;
+ m_pFramesSize = new unsigned int[m_nFrames];
+
+ m_bUsePAL = (cDevice::PrimaryDevice()->GetVideoSystem() == vsPAL);
+ m_nWidth = 720;
+ m_nHeight = m_bUsePAL ? 576 : 480;
+
+
+ m_nMaxMPEGSize = m_nWidth*m_nHeight * 3; //It see for me 500kb are enough, therefore should the double really enough memory
+
+ /* Allocate bufers */
+ if(NULL == (m_pMPEG=(uint8_t *)malloc(m_nMaxMPEGSize*3)) //~1200kb
+ || NULL == (m_pImageRGB=(uint8_t *)malloc(m_nWidth*m_nHeight*3)) //~1200kb
+ || NULL == (m_pImageFilled=(uint8_t *)malloc(m_nWidth*m_nHeight*3)) //~1200kb
+ || NULL == (m_pImageYUV=(uint8_t *)malloc(m_nWidth*m_nHeight*3/2))) //~600kb
+ {
+ esyslog("imageplugin: Failed to alloc memory for bitmaps.");
+ return;
+ }
+
+ m_pavCodec = fn_avcodec_find_encoder(CODEC_ID_MPEG2VIDEO);
+ if (!m_pavCodec) {
+ esyslog("imageplugin: Failed to find CODEC_ID_MPEG2VIDEO.");
+ return;
+ }
+ m_bLoaded = true;
+}
+
+bool cEncode::Register()
+{
+ #ifndef HAVE_FFMPEG_STATIC
+ if(!InitLibAVCodec()) {
+ esyslog("imageplugin: Failed to InitLibAVCodec.");
+ return false;
+ }
+ #endif
+ fn_avcodec_init();
+ fn_avcodec_register_all();
+ return true;
+}
+
+void cEncode::UnRegister()
+{
+#ifndef HAVE_FFMPEG_STATIC
+ CloseLibAVCodec();
+#endif
+}
+
+void cEncode::ClearRGBMem()
+{
+ if(m_pImageRGB && m_bLoaded)
+ memset(m_pImageRGB,0,m_nWidth*m_nHeight*3 );
+}
+
+/*******************************************************************************
+
+*/
+cEncode::~cEncode(void)
+{
+ if(m_pImageYUV)
+ free(m_pImageYUV);
+
+ if(m_pImageFilled)
+ free(m_pImageFilled);
+
+ if(m_pImageRGB)
+ free(m_pImageRGB);
+
+ if(m_pMPEG)
+ free(m_pMPEG);
+ delete m_pFramesSize;
+}
+
+/*******************************************************************************
+
+*/
+bool cEncode::Encode()
+{
+ m_nData = 0;
+
+ if (!m_bLoaded){
+ dsyslog("imageplugin: libavcodec is'nt successful loaded.");
+ return false;
+ }
+
+ bool bSuccess = false;
+ unsigned int i;
+ AVCodecContext *pAVCC = NULL;
+ AVFrame *pAVF = NULL;
+ int nSize=m_nWidth*m_nHeight;
+
+ if(NULL == (pAVCC = fn_avcodec_alloc_context())
+ || NULL == (pAVF = fn_avcodec_alloc_frame())) {
+ esyslog("imageplugin: Failed to alloc memory for AVCODEC and CONTEXT.");
+ goto encexit;
+ }
+
+ pAVCC->bit_rate=1000000; //1000kbit
+ pAVCC->width = m_nWidth;
+ pAVCC->height = m_nHeight;
+ pAVCC->frame_rate=GetFrameRate();
+ pAVCC->frame_rate_base=1;
+ pAVCC->gop_size=m_nFrames-1; //IPB //1 => Encode only I-Frames, bigger
+ pAVCC->max_b_frames=1;
+ pAVCC->flags |= CODEC_FLAG_QSCALE;
+
+ if (fn_avcodec_open(pAVCC, m_pavCodec)<0) {
+ esyslog("imageplugin: Coldn't open Codec.");
+ goto encexit;
+ }
+
+ pAVF->data[0]=m_pImageYUV;
+ pAVF->data[1]=m_pImageYUV+nSize;
+ pAVF->data[2]=pAVF->data[1]+nSize/4;
+ pAVF->linesize[0]=m_nWidth;
+ pAVF->linesize[1]=pAVF->linesize[2]=m_nWidth/2;
+ pAVF->quality = 1;
+
+ // Convert RGB to YUV
+ if(!fn_avpicture_fill((AVPicture*)m_pImageFilled, m_pImageRGB, PIX_FMT_RGB24,
+ m_nWidth, m_nHeight)) {
+ esyslog("imageplugin: failed avpicture_fill");
+ goto encexit;
+ }
+
+ if(fn_img_convert((AVPicture*)pAVF->data, PIX_FMT_YUV420P,
+ (AVPicture*)m_pImageFilled, PIX_FMT_RGB24, m_nWidth, m_nHeight)) {
+ esyslog("imageplugin: failed convert RGB to YUV");
+ goto encexit;
+ }
+
+ // Encode Frames which defined with m_nFrames
+ for(i=0; i<m_nFrames && m_nData < m_nMaxMPEGSize; ++i)
+ {
+ int nFrameSize = fn_avcodec_encode_video(pAVCC, m_pMPEG + m_nData, m_nMaxMPEGSize - m_nData, pAVF);
+ if(nFrameSize < 0)
+ {
+ esyslog("imageplugin: Failed add %d frame, insufficient memory.",i);
+ bSuccess = false;
+ break;
+ }
+ bSuccess = true;
+ m_nData += nFrameSize;
+ *(m_pFramesSize + i) = nFrameSize;
+ }
+
+ if(bSuccess && m_nData < m_nMaxMPEGSize) // if sufficient place present
+ {
+ //add four bytes end sequnce
+ memcpy(m_pMPEG + m_nData,"\0x00\0x00\0x01\0xb7",4);
+ m_nData += 4;
+ *(m_pFramesSize + i - 1) += 4;
+
+ }
+ else bSuccess = false;
+
+ #ifdef TESTCODE
+ if(bSuccess)
+ Save("/tmp/imagetest.mpg");
+ #endif
+
+encexit:
+ if (pAVCC)
+ {
+ fn_avcodec_close(pAVCC);
+ free(pAVCC);
+ }
+
+ if(pAVF)
+ {
+ free(pAVF);
+ }
+ return bSuccess;
+}
+
+
+
+
+#ifdef TESTCODE
+/*******************************************************************************
+
+*/
+bool cEncode::Load(const char* szFileName)
+{
+ int nSize = m_nWidth*m_nHeight;
+ FILE *inf=fopen(szFileName, "r");
+ if(inf)
+ {
+ fseek(inf, 15, SEEK_SET);
+ fread(m_pImageRGB, 1, nSize*3, inf);
+ fclose(inf);
+ return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+
+*/
+bool cEncode::Save(const char* szFileName) const
+{
+ if(m_pMPEG && m_nData)
+ {
+ FILE * outf=fopen(szFileName, "w");
+ if(outf) {
+ fwrite(m_pMPEG, 1, m_nData, outf);
+ fclose(outf);
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+
+#if 0
+int main(){
+ cEncode e;
+ e.Load("test.pnm");
+ e.Encode();
+ e.Save("test.mpg");
+ return 0;
+}
+#endif
diff --git a/liboutput/encode.h b/liboutput/encode.h
new file mode 100644
index 0000000..0491927
--- /dev/null
+++ b/liboutput/encode.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * encode.h
+ *
+ * (C) Copyright 2004 Andreas Brachold <vdr04-at-deltab.de>
+ * Created: Thu Aug 5 2004
+ *
+ ****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ENCODE_H
+#define _ENCODE_H
+
+extern "C"
+{
+#ifdef HAVE_FFMPEG_STATIC
+# include <libavcodec/avcodec.h>
+#else
+# include <ffmpeg/avcodec.h>
+//#include <libavcodec/avcodec.h>
+#endif
+}
+
+//#define TESTCODE
+
+class cEncode
+{
+ AVCodec *m_pavCodec;
+ unsigned int m_nMaxMPEGSize;
+ uint8_t *m_pImageFilled;
+ uint8_t *m_pImageYUV;
+protected:
+ const unsigned int m_nFrames;
+ unsigned int m_nData;
+ uint8_t *m_pMPEG;
+ uint8_t *m_pImageRGB;
+ bool m_bUsePAL;
+ unsigned int m_nWidth;
+ unsigned int m_nHeight;
+ unsigned int* m_pFramesSize;
+
+#ifndef HAVE_FFMPEG_STATIC
+private:
+ static void *m_hLibAvcodec;
+protected:
+ static bool InitLibAVCodec(void);
+ static void CloseLibAVCodec(void);
+#endif
+ bool m_bLoaded;
+public:
+ cEncode();
+ virtual ~cEncode();
+
+ /*Load Shared Library and Register Codec*/
+ static bool Register();
+ /*UnLoad Shared*/
+ static void UnRegister();
+
+ bool Encode();
+ inline const uint8_t *Data() const { return m_pMPEG; }
+ inline unsigned int Size() const { return m_nData; }
+ inline unsigned int GetFrames() const { return m_nFrames; }
+ inline unsigned int GetFrameRate() const { return m_bUsePAL?25:30; }
+
+ inline unsigned int GetHeight() const { return m_nHeight; }
+ inline unsigned int GetWidth() const { return m_nWidth; }
+ inline unsigned int GetBorderHeight() const { return 16; }
+ inline unsigned int GetBorderWidth() const { return 16; }
+
+ inline uint8_t *GetRGBMem() { return m_pImageRGB; }
+#ifdef TESTCODE
+ bool Load(const char* szFileName);
+ bool Save(const char* szFileName) const;
+#endif
+ void ClearRGBMem ();
+};
+
+#endif /* _ENCODE_H */
diff --git a/liboutput/stillimage-player.c b/liboutput/stillimage-player.c
new file mode 100644
index 0000000..947157e
--- /dev/null
+++ b/liboutput/stillimage-player.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * stillimage-player.c
+ * (C) Copyright 2004 Andreas Brachold <vdr04-at-deltab.de>
+ * Created: Thu Aug 5 2004
+ *
+ ****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "stillimage-player.h"
+#include "stillimage.h"
+
+cStillImagePlayer::cStillImagePlayer(ePlayMode PlayMode)
+ : cPlayer(PlayMode)
+ , m_bActive(false)
+ , m_StillImage(this)
+{
+}
+
+cStillImagePlayer::~cStillImagePlayer()
+{
+ Detach();
+}
+
+void cStillImagePlayer::Activate(bool On) {
+ if (On) {
+ m_bActive=m_StillImage.Init();
+ } else {
+ if (m_bActive) {
+ m_StillImage.Stop();
+ m_bActive=false;
+ }
+ }
+}
+
+void cStillImagePlayer::Play(const uchar *Data, int Length) {
+#if VDRVERSNUM < 10318
+ PlayVideo(Data, Length);
+#else
+ PlayPes(Data, Length,true);
+#endif
+}
+
+bool cStillImagePlayer::Wait() {
+ cPoller Poller;
+ return DevicePoll(Poller, 100);
+}
diff --git a/liboutput/stillimage-player.h b/liboutput/stillimage-player.h
new file mode 100644
index 0000000..b3aa712
--- /dev/null
+++ b/liboutput/stillimage-player.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * stillimage-player.h
+ * (C) Copyright 2004 Andreas Brachold <vdr04-at-deltab.de>
+ * Created: Thu Aug 5 2004
+ *
+ ****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef STILLIMAGEPLAYER_H
+#define STILLIMAGEPLAYER_H
+
+#include <vdr/thread.h>
+#include <vdr/player.h>
+
+#include "stillimage.h"
+
+class cStillImagePlayer
+ : public cPlayer {
+ friend class cStillImage;
+ bool m_bActive;
+protected:
+ cStillImage m_StillImage;
+public:
+ cStillImagePlayer(ePlayMode PlayMode);
+ virtual ~cStillImagePlayer();
+
+ inline unsigned int UseWidth() const
+ { return m_StillImage.GetWidth() - (m_StillImage.GetBorderWidth()*2); }
+ inline unsigned int UseHeight() const
+ { return m_StillImage.GetHeight() - (m_StillImage.GetBorderHeight()*2); }
+protected:
+ virtual void Activate(bool On);
+ void Play(const uchar *Data, int Length);
+ bool Wait();
+
+ virtual bool Worker(bool bDoIt) = 0;
+};
+
+
+#endif
diff --git a/liboutput/stillimage.c b/liboutput/stillimage.c
new file mode 100644
index 0000000..9058ff0
--- /dev/null
+++ b/liboutput/stillimage.c
@@ -0,0 +1,210 @@
+/***************************************************************************
+ * stillimage.c
+ * (C) Copyright 2004 <vdr04-at-deltab.de>
+ * Created: Thu Aug 5 2004
+ *
+ * parts of the code (c) Peter Seyringer
+ * (c) Marcel Wiesweg
+ ****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <string.h>
+#include <unistd.h>
+
+#include "stillimage.h"
+#include "stillimage-player.h"
+
+
+
+cStillImage::cStillImage(cStillImagePlayer *pl)
+{
+ m_bThreadRun=false;
+ m_bEncodeRequired = false;
+ player=pl;
+}
+
+cStillImage::~cStillImage()
+{
+
+}
+
+bool cStillImage::Init()
+{
+ return Start();
+}
+
+void cStillImage::Stop()
+{
+ if (!m_bThreadRun)
+ return;
+ m_bThreadRun=false;
+
+ Cancel(3);
+}
+
+void cStillImage::Action(void)
+{
+ m_bThreadRun=true;
+ bool bMPEGValid = false;
+ bool bQueueEmpty = false;
+ bool bFreeze = true;
+
+ unsigned int nFrame = 0,nFrameOff=0;
+ int nMircoSekWait;
+ while (m_bThreadRun) {
+
+ nMircoSekWait = 10000;
+ bQueueEmpty = player->Worker(false);
+ if(!bQueueEmpty)
+ {
+ if(!bFreeze)
+ {
+ player->DeviceFreeze();
+ bFreeze = true;
+ }
+ player->Worker(true);
+ }
+
+ if(m_bEncodeRequired
+ && bQueueEmpty)
+ {
+ //convert data to MPEG
+ Lock();
+ bMPEGValid = Encode();
+ Unlock();
+
+ if (!m_bThreadRun)
+ break;
+ m_bEncodeRequired = false;
+ nFrame = 0;
+ nFrameOff=0;
+ if(bFreeze)
+ {
+ player->DevicePlay();
+ bFreeze = false;
+ }
+
+ }
+
+
+ if(bMPEGValid
+ && bQueueEmpty)
+ {
+ /* Methode A ************************************************************/
+ /*timeval timenow,diff,timestart;
+ gettimeofday(&timestart, 0);
+
+ for (int i=1;i<=25 && player->active;i++) {
+ gettimeofday(&timenow, 0);
+ timersub(&timenow, &timestart, &diff);
+ BuildPesPacket(Data(), Size(),(int)(diff.tv_sec*90000.0 + (diff.tv_usec*90000.0)/1000000.0));
+ player->Wait();
+ }*/
+
+ /* Methode B ************************************************************/
+ //for (int i=1;i<= 25 && player->m_bActive;i++) {
+ // BuildPesPacket(Data(), Size(),i);
+ //}
+
+ /* Methode C ************************************************************/
+ //BuildPesPacket(Data(), Size(),1);
+
+ /* Methode D ************************************************************/
+ //player->DeviceStillPicture(Data(), Size());
+
+ /* Methode E ************************************************************/
+
+
+ unsigned int nFrameSize = *(m_pFramesSize + nFrame);
+ if(nFrameSize) // Skip empty Frames
+ {
+ BuildPesPacket(Data() + nFrameOff, nFrameSize,1);
+ nFrameOff += nFrameSize;
+ }
+ if(++nFrame>=m_nFrames)
+ {
+ nFrame = 0;
+ nFrameOff = 0;
+ }
+
+ nMircoSekWait = (1000000/(GetFrameRate()*4)); // Wait duration off 1/4 frame
+
+ if (!m_bThreadRun)
+ break;
+ }
+ //Reduce CPU load!!!
+ usleep(max(10000,nMircoSekWait));
+ }
+ m_bThreadRun=false;
+}
+
+
+//taken from mp1osd.c
+void cStillImage::BuildPesPacket(const unsigned char *data, int len, int timestamp) {
+#define PES_MAX_SIZE 2048
+ int ptslen = timestamp ? 5 : 1;
+ static unsigned char pes_header[PES_MAX_SIZE];
+
+ // startcode:
+ pes_header[0] = pes_header[1] = 0;
+ pes_header[2] = 1;
+ pes_header[3] = 0xe0;
+
+ while (len > 0)
+ {
+ int payload_size = len; // data + PTS
+
+ if (6 + ptslen + payload_size > PES_MAX_SIZE)
+ payload_size = PES_MAX_SIZE - (6 + ptslen);
+
+ // construct PES header: (code from ffmpeg's libav)
+ // packetsize:
+ pes_header[4] = (ptslen + payload_size) >> 8;
+ pes_header[5] = (ptslen + payload_size) & 255;
+
+ if (ptslen == 5)
+ {
+ int x;
+
+ // presentation time stamp:
+ x = (0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1;
+ pes_header[8] = x;
+ x = ((((timestamp >> 15) & 0x7fff) << 1) | 1);
+ pes_header[7] = x >> 8;
+ pes_header[8] = x & 255;
+ x = ((((timestamp) & 0x7fff) << 1) | 1);
+ pes_header[9] = x >> 8;
+ pes_header[10] = x & 255;
+ }
+ else
+ {
+ // stuffing and header bits:
+ pes_header[6] = 0x0f;
+ }
+
+ memcpy (&pes_header[6 + ptslen], data, payload_size);
+ player->Wait();
+ player->Play(pes_header, 6 + ptslen + payload_size);
+
+ len -= payload_size;
+ data += payload_size;
+ ptslen = 1; // store PTS only once, at first packet!
+
+ }
+}
diff --git a/liboutput/stillimage.h b/liboutput/stillimage.h
new file mode 100644
index 0000000..453692c
--- /dev/null
+++ b/liboutput/stillimage.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * stillimage.h
+ * (C) Copyright 2004 Andreas Brachold <vdr04-at-deltab.de>
+ * Created: Thu Aug 5 2004
+ *
+ ****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef STILLIMAGE_H
+#define STILLIMAGE_H
+
+#include <vdr/thread.h>
+#include "encode.h"
+
+class cStillImagePlayer;
+
+
+class cStillImage
+: public cThread
+, public cEncode {
+
+ cStillImagePlayer *player;
+ volatile bool m_bThreadRun;
+ volatile bool m_bEncodeRequired;
+protected:
+ virtual void Action(void);
+ void BuildPesPacket(const unsigned char *data, int len, int timestamp);
+
+public:
+ cStillImage(cStillImagePlayer *);
+ virtual ~cStillImage();
+
+ bool Init();
+ void Stop();
+ bool EncodeRequired() const {return m_bEncodeRequired;}
+ void EncodeRequired(bool b) {m_bEncodeRequired = b;}
+};
+
+#endif