diff --git a/softhddev.c b/softhddev.c index 5d0f8fb..558fed7 100644 --- a/softhddev.c +++ b/softhddev.c @@ -1269,6 +1269,10 @@ struct __video_stream__ static VideoStream MyVideoStream[1]; ///< normal video stream +#ifdef USE_PIP +static VideoStream PipVideoStream[1]; ///< pip video stream +#endif + #ifdef DEBUG uint32_t VideoSwitch; ///< debug video switch ticks static int VideoMaxPacketSize; ///< biggest used packet buffer @@ -1676,6 +1680,7 @@ static void StartVideo(void) } MyVideoStream->CodecID = CODEC_ID_NONE; MyVideoStream->LastCodecID = CODEC_ID_NONE; + } VideoPacketInit(MyVideoStream); } @@ -1895,7 +1900,7 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size) Debug(3, "video: mpeg2 detected ID %02x\n", check[3]); stream->CodecID = CODEC_ID_MPEG2VIDEO; } -#ifdef DEBUG +#ifdef noDEBUG // pip pes packet has no lenght if (ValidateMpeg(data, size)) { Debug(3, "softhddev/video: invalid mpeg2 video packet\n"); } @@ -1924,26 +1929,6 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size) return size; } -/** -** Play video packet. -** -** @param data data of exactly one complete PES packet -** @param size size of PES packet -** -** @return number of bytes used, 0 if internal buffer are full. -** -*/ -int PlayVideo2(const uint8_t * data, int size) -{ - static VideoStream *stream; - - if (!stream) { // test hack v1 - stream = MyVideoStream; - } - - return PlayVideo3(stream, data, size); -} - /** ** Play video packet. ** @@ -2924,3 +2909,82 @@ void ScaleVideo(int x, int y, int width, int height) VideoSetOutputPosition(MyVideoStream->HwDecoder, x, y, width, height); } } + +////////////////////////////////////////////////////////////////////////////// +// PIP +////////////////////////////////////////////////////////////////////////////// + +#ifdef USE_PIP + +/** +** Start PIP stream. +** +** @param x video window x coordinate OSD relative +** @param y video window y coordinate OSD relative +** @param width video window width OSD relative +** @param height video window height OSD relative +** @param pip_x pip window x coordinate OSD relative +** @param pip_y pip window y coordinate OSD relative +** @param pip_width pip window width OSD relative +** @param pip_height pip window height OSD relative +*/ +void PipStart(int x, int y, int width, int height, int pip_x, int pip_y, + int pip_width, int pip_height) +{ + if (!MyVideoStream->HwDecoder) { // video not running + return; + } + + ScaleVideo(x, y, width, height); + + if (!PipVideoStream->Decoder) { + PipVideoStream->SkipStream = 1; + if ((PipVideoStream->HwDecoder = VideoNewHwDecoder(PipVideoStream))) { + PipVideoStream->Decoder = + CodecVideoNewDecoder(PipVideoStream->HwDecoder); + PipVideoStream->SkipStream = 0; + + PipVideoStream->CodecID = CODEC_ID_NONE; + PipVideoStream->LastCodecID = CODEC_ID_NONE; + + VideoPacketInit(PipVideoStream); + VideoSetOutputPosition(PipVideoStream->HwDecoder, pip_x, pip_y, + pip_width, pip_height); + } + } +} + +/** +** Stop PIP. +*/ +void PipStop(void) +{ + if (PipVideoStream->Decoder) { + PipVideoStream->SkipStream = 1; + CodecVideoClose(PipVideoStream->Decoder); + CodecVideoDelDecoder(PipVideoStream->Decoder); + PipVideoStream->Decoder = NULL; + } + if (PipVideoStream->HwDecoder) { + VideoDelHwDecoder(PipVideoStream->HwDecoder); + PipVideoStream->HwDecoder = NULL; + } + VideoPacketExit(PipVideoStream); + + PipVideoStream->NewStream = 1; +} + +/** +** PIP play video packet. +** +** @param data data of exactly one complete PES packet +** @param size size of PES packet +** +** @return number of bytes used, 0 if internal buffer are full. +*/ +int PipPlayVideo(const uint8_t * data, int size) +{ + return PlayVideo3(PipVideoStream, data, size); +} + +#endif diff --git a/softhddev.h b/softhddev.h index 564dcba..4075fbd 100644 --- a/softhddev.h +++ b/softhddev.h @@ -44,8 +44,6 @@ extern "C" /// C plugin play video packet extern int PlayVideo(const uint8_t *, int); - /// C plugin play video packet (next version) - extern int PlayVideo2(const uint8_t *, int); /// C plugin play TS video packet extern void PlayTsVideo(const uint8_t *, int); /// C plugin grab an image @@ -99,6 +97,13 @@ extern "C" extern void GetStats(int *, int *, int *, int *); /// C plugin scale video extern void ScaleVideo(int, int, int, int); + + /// Pip start + extern void PipStart(int, int, int, int, int, int, int, int); + /// Pip stop + extern void PipStop(void); + /// Pip play video packet + extern int PipPlayVideo(const uint8_t *, int); #ifdef __cplusplus } #endif diff --git a/softhddevice.cpp b/softhddevice.cpp index 722bad9..e1c4e31 100644 --- a/softhddevice.cpp +++ b/softhddevice.cpp @@ -140,6 +140,25 @@ static char *ConfigX11Display; ///< config x11 display static char *ConfigAudioDevice; ///< config audio stereo device static char *ConfigAC3Device; ///< config audio passthrough device +#ifdef USE_PIP +static int ConfigPipX; ///< config pip pip x in % +static int ConfigPipY; ///< config pip pip y in % +static int ConfigPipWidth; ///< config pip pip width in % +static int ConfigPipHeight; ///< config pip pip height in % +static int ConfigPipVideoX; ///< config pip video x in % +static int ConfigPipVideoY; ///< config pip video y in % +static int ConfigPipVideoWidth; ///< config pip video width in % +static int ConfigPipVideoHeight; ///< config pip video height in % +static int ConfigPipAltX; ///< config pip alt. pip x in % +static int ConfigPipAltY; ///< config pip alt. pip y in % +static int ConfigPipAltWidth; ///< config pip alt. pip width in % +static int ConfigPipAltHeight; ///< config pip alt. pip height in % +static int ConfigPipAltVideoX; ///< config pip alt. video x in % +static int ConfigPipAltVideoY; ///< config pip alt. video y in % +static int ConfigPipAltVideoWidth; ///< config pip alt. video width in % +static int ConfigPipAltVideoHeight; ///< config pip alt. video height in % +#endif + static volatile int DoMakePrimary; ///< switch primary device to this #define SUSPEND_EXTERNAL -1 ///< play external suspend mode @@ -605,6 +624,27 @@ class cMenuSetupSoft:public cMenuSetupPage int AudioMaxCompression; int AudioStereoDescent; int AudioBufferTime; + +#ifdef USE_PIP + int Pip; + int PipX; + int PipY; + int PipWidth; + int PipHeight; + int PipVideoX; + int PipVideoY; + int PipVideoWidth; + int PipVideoHeight; + int PipAltX; + int PipAltY; + int PipAltWidth; + int PipAltHeight; + int PipAltVideoX; + int PipAltVideoY; + int PipAltVideoWidth; + int PipAltVideoHeight; +#endif + /// @} private: inline cOsdItem * CollapsedItem(const char *, int &, const char * = NULL); @@ -823,6 +863,41 @@ void cMenuSetupSoft::Create(void) Add(new cMenuEditIntItem(tr("Audio buffer size (ms)"), &AudioBufferTime, 0, 1000)); } +#ifdef USE_PIP + // + // PIP + // + Add(CollapsedItem(tr("Picture-In-Picture"), Pip)); + if (Pip) { + // FIXME: predefined modes/custom mode + Add(new cMenuEditIntItem(tr("Pip X (%)"), &PipX, 0, 100)); + Add(new cMenuEditIntItem(tr("Pip Y (%)"), &PipY, 0, 100)); + Add(new cMenuEditIntItem(tr("Pip Width (%)"), &PipWidth, 0, 100)); + Add(new cMenuEditIntItem(tr("Pip Height (%)"), &PipHeight, 0, 100)); + Add(new cMenuEditIntItem(tr("Video X (%)"), &PipVideoX, 0, 100)); + Add(new cMenuEditIntItem(tr("Video Y (%)"), &PipVideoY, 0, 100)); + Add(new cMenuEditIntItem(tr("Video Width (%)"), &PipVideoWidth, 0, + 100)); + Add(new cMenuEditIntItem(tr("Video Height (%)"), &PipVideoHeight, 0, + 100)); + Add(new cMenuEditIntItem(tr("Alternative Pip X (%)"), &PipAltX, 0, + 100)); + Add(new cMenuEditIntItem(tr("Alternative Pip Y (%)"), &PipAltY, 0, + 100)); + Add(new cMenuEditIntItem(tr("Alternative Pip Width (%)"), &PipAltWidth, + 0, 100)); + Add(new cMenuEditIntItem(tr("Alternative Pip Height (%)"), + &PipAltHeight, 0, 100)); + Add(new cMenuEditIntItem(tr("Alternative Video X (%)"), &PipAltVideoX, + 0, 100)); + Add(new cMenuEditIntItem(tr("Alternative Video Y (%)"), &PipAltVideoY, + 0, 100)); + Add(new cMenuEditIntItem(tr("Alternative Video Width (%)"), + &PipAltVideoWidth, 0, 100)); + Add(new cMenuEditIntItem(tr("Alternative Video Height (%)"), + &PipAltVideoHeight, 0, 100)); + } +#endif SetCurrent(Get(current)); // restore selected menu entry Display(); // display build menu @@ -837,6 +912,7 @@ eOSState cMenuSetupSoft::ProcessKey(eKeys key) int old_general; int old_video; int old_audio; + int old_pip; int old_osd_size; int old_resolution_shown[RESOLUTIONS]; int i; @@ -844,6 +920,9 @@ eOSState cMenuSetupSoft::ProcessKey(eKeys key) old_general = General; old_video = Video; old_audio = Audio; +#ifdef USE_PIP + old_pip = Pip; +#endif old_osd_size = OsdSize; memcpy(old_resolution_shown, ResolutionShown, sizeof(ResolutionShown)); state = cMenuSetupPage::ProcessKey(key); @@ -852,6 +931,9 @@ eOSState cMenuSetupSoft::ProcessKey(eKeys key) // update menu only, if something on the structure has changed // this is needed because VDR menus are evil slow if (old_general != General || old_video != Video || old_audio != Audio +#ifdef USE_PIP + || old_pip != Pip +#endif || old_osd_size != OsdSize) { Create(); // update menu } else { @@ -956,6 +1038,28 @@ cMenuSetupSoft::cMenuSetupSoft(void) AudioStereoDescent = ConfigAudioStereoDescent; AudioBufferTime = ConfigAudioBufferTime; +#ifdef USE_PIP + // + // PIP + // + Pip = 0; + PipX = ConfigPipX; + PipY = ConfigPipY; + PipWidth = ConfigPipWidth; + PipHeight = ConfigPipHeight; + PipVideoX = ConfigPipVideoX; + PipVideoY = ConfigPipVideoY; + PipVideoWidth = ConfigPipVideoWidth; + PipVideoHeight = ConfigPipVideoHeight; + PipAltX = ConfigPipAltX; + PipAltY = ConfigPipAltY; + PipAltWidth = ConfigPipAltWidth; + PipAltHeight = ConfigPipAltHeight; + PipAltVideoX = ConfigPipAltVideoX; + PipAltVideoY = ConfigPipAltVideoY; + PipAltVideoWidth = ConfigPipAltVideoWidth; + PipAltVideoHeight = ConfigPipAltVideoHeight; +#endif Create(); } @@ -1085,6 +1189,27 @@ void cMenuSetupSoft::Store(void) AudioStereoDescent); AudioSetStereoDescent(ConfigAudioStereoDescent); SetupStore("AudioBufferTime", ConfigAudioBufferTime = AudioBufferTime); + +#ifdef USE_PIP + SetupStore("pip.X", ConfigPipX = PipX); + SetupStore("pip.Y", ConfigPipY = PipY); + SetupStore("pip.Width", ConfigPipWidth = PipWidth); + SetupStore("pip.Height", ConfigPipHeight = PipHeight); + SetupStore("pip.VideoX", ConfigPipVideoX = PipVideoX); + SetupStore("pip.VideoY", ConfigPipVideoY = PipVideoY); + SetupStore("pip.VideoWidth", ConfigPipVideoWidth = PipVideoWidth); + SetupStore("pip.VideoHeight", ConfigPipVideoHeight = PipVideoHeight); + SetupStore("pip.Alt.X", ConfigPipAltX = PipAltX); + SetupStore("pip.Alt.Y", ConfigPipAltY = PipAltY); + SetupStore("pip.Alt.Width", ConfigPipAltWidth = PipAltWidth); + SetupStore("pip.Alt.Height", ConfigPipAltHeight = PipAltHeight); + SetupStore("pip.Alt.VideoX", ConfigPipAltVideoX = PipAltVideoX); + SetupStore("pip.Alt.VideoY", ConfigPipAltVideoY = PipAltVideoY); + SetupStore("pip.Alt.VideoWidth", ConfigPipAltVideoWidth = + PipAltVideoWidth); + SetupStore("pip.Alt.VideoHeight", ConfigPipAltVideoHeight = + PipAltVideoHeight); +#endif } ////////////////////////////////////////////////////////////////////////////// @@ -1184,8 +1309,6 @@ cSoftHdControl::~cSoftHdControl() #ifdef USE_PIP -static int OsdPipTest; ///< OSD pip test flag - ////////////////////////////////////////////////////////////////////////////// // cReceiver ////////////////////////////////////////////////////////////////////////////// @@ -1210,7 +1333,8 @@ class cSoftReceiver:public cReceiver ** ** @param channel channel to receive. */ -cSoftReceiver::cSoftReceiver(const cChannel * channel):cReceiver(channel) +cSoftReceiver::cSoftReceiver(const cChannel * channel):cReceiver(channel, + LIVEPRIORITY) { fprintf(stderr, "pip: v-pid: %04x\n", channel->Vpid()); SetPids(NULL); // clear all pids, we want video only @@ -1222,6 +1346,7 @@ cSoftReceiver::cSoftReceiver(const cChannel * channel):cReceiver(channel) */ cSoftReceiver::~cSoftReceiver() { + Detach(); } /** @@ -1233,7 +1358,11 @@ void cSoftReceiver::Activate(bool on) { fprintf(stderr, "pip: activate %d\n", on); - OsdPipTest = on; + if (on) { + PipStart(0, 0, 0, 0, 50, 50, 355, 200); + } else { + PipStop(); + } } /// @@ -1258,12 +1387,15 @@ static void PipPesParse(const uint8_t * data, int size, int is_start) } if (is_start) { // start of pes packet if (pes_index) { - fprintf(stderr, "pip: pes packet %8d %02x%02x\n", pes_index, - pes_buf[2], pes_buf[3]); + if (0) { + fprintf(stderr, "pip: pes packet %8d %02x%02x\n", pes_index, + pes_buf[2], pes_buf[3]); + } if (pes_buf[0] || pes_buf[1] || pes_buf[2] != 0x01) { - fprintf(stderr, "pip: invalid pes packet %d\n", pes_index); + // FIXME: first should always fail + esyslog(tr("pip: invalid pes packet %d\n"), pes_index); } else { - PlayVideo2(pes_buf, pes_index); + PipPlayVideo(pes_buf, pes_index); // FIXME: buffer full: pes packet is dropped } pes_index = 0; @@ -1292,14 +1424,8 @@ static void PipPesParse(const uint8_t * data, int size, int is_start) */ void cSoftReceiver::Receive(uchar * data, int size) { - static int x; const uint8_t *p; - if (!x) { - fprintf(stderr, "pip: receive %p(%d)\n", data, size); - x++; - } - p = data; while (size >= TS_PACKET_SIZE) { int payload; @@ -1409,7 +1535,13 @@ void cSoftHdMenu::Create(void) SetHasHotkeys(); Add(new cOsdItem(hk(tr("Suspend SoftHdDevice")), osUser1)); #ifdef USE_PIP - Add(new cOsdItem(hk(tr("PIP")), osUser2)); + Add(new cOsdItem(hk(tr("PIP start")), osUser2)); + Add(new cOsdItem(hk(tr("PIP zapmode")), osUser3)); + Add(new cOsdItem(hk(tr("PIP channel +")), osUser4)); + Add(new cOsdItem(hk(tr("PIP channel -")), osUser5)); + Add(new cOsdItem(hk(tr("PIP swap channels")), osUser6)); + Add(new cOsdItem(hk(tr("PIP swap position")), osUser7)); + Add(new cOsdItem(hk(tr("PIP close")), osUser8)); #endif Add(new cOsdItem(NULL, osUnknown, false)); Add(new cOsdItem(NULL, osUnknown, false)); @@ -2030,12 +2162,6 @@ void cSoftHdDevice::SetVolumeDevice(int volume) int cSoftHdDevice::PlayVideo(const uchar * data, int length) { //dsyslog("[softhddev]%s: %p %d\n", __FUNCTION__, data, length); -#ifdef USE_PIP - if (OsdPipTest) { - return length; - } -#endif - return::PlayVideo(data, length); }