diff options
author | Johns <johns98@gmx.net> | 2013-01-03 18:52:34 +0100 |
---|---|---|
committer | Johns <johns98@gmx.net> | 2013-01-03 18:52:34 +0100 |
commit | d42475f2dc42650e38069a22f020635132dd5341 (patch) | |
tree | 1313b8b0c3cab725b058efa4b3f7973fba9573cd /softhddevice.cpp | |
parent | 7cf6c1ab2baef9d83c9c44ea663ef6b997f40d9c (diff) | |
download | vdr-plugin-softhddevice-d42475f2dc42650e38069a22f020635132dd5341.tar.gz vdr-plugin-softhddevice-d42475f2dc42650e38069a22f020635132dd5341.tar.bz2 |
Prepared reentrant video stream.
Diffstat (limited to 'softhddevice.cpp')
-rw-r--r-- | softhddevice.cpp | 225 |
1 files changed, 217 insertions, 8 deletions
diff --git a/softhddevice.cpp b/softhddevice.cpp index f0f8c38..722bad9 100644 --- a/softhddevice.cpp +++ b/softhddevice.cpp @@ -50,7 +50,7 @@ extern "C" /// vdr-plugin version number. /// Makefile extracts the version number for generating the file name /// for the distribution archive. -static const char *const VERSION = "0.5.3" +static const char *const VERSION = "0.6.0" #ifdef GIT_REV "-GIT" GIT_REV #endif @@ -1179,6 +1179,201 @@ cSoftHdControl::~cSoftHdControl() } ////////////////////////////////////////////////////////////////////////////// +// PIP +////////////////////////////////////////////////////////////////////////////// + +#ifdef USE_PIP + +static int OsdPipTest; ///< OSD pip test flag + +////////////////////////////////////////////////////////////////////////////// +// cReceiver +////////////////////////////////////////////////////////////////////////////// + +#include <vdr/receiver.h> + +/** +** Receiver class for PIP mode. +*/ +class cSoftReceiver:public cReceiver +{ + protected: + virtual void Activate(bool); + virtual void Receive(uchar *, int); + public: + cSoftReceiver(const cChannel *); ///< receiver constructor + virtual ~ cSoftReceiver(); ///< receiver destructor +}; + +/** +** Receiver constructor. +** +** @param channel channel to receive. +*/ +cSoftReceiver::cSoftReceiver(const cChannel * channel):cReceiver(channel) +{ + fprintf(stderr, "pip: v-pid: %04x\n", channel->Vpid()); + SetPids(NULL); // clear all pids, we want video only + AddPid(channel->Vpid()); +} + +/** +** Receiver destructor. +*/ +cSoftReceiver::~cSoftReceiver() +{ +} + +/** +** Called before the receiver gets attached or detached. +** +** @param on flag attached, detached +*/ +void cSoftReceiver::Activate(bool on) +{ + fprintf(stderr, "pip: activate %d\n", on); + + OsdPipTest = on; +} + +/// +/// Parse packetized elementary stream. +/// +/// @param data payload data of transport stream +/// @param size number of payload data bytes +/// @param is_start flag, start of pes packet +/// +static void PipPesParse(const uint8_t * data, int size, int is_start) +{ + static uint8_t *pes_buf; + static int pes_size; + static int pes_index; + + // FIXME: quick&dirty + + if (!pes_buf) { + pes_size = 500 * 1024 * 1024; + pes_buf = (uint8_t *) malloc(pes_size); + pes_index = 0; + } + 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 (pes_buf[0] || pes_buf[1] || pes_buf[2] != 0x01) { + fprintf(stderr, "pip: invalid pes packet %d\n", pes_index); + } else { + PlayVideo2(pes_buf, pes_index); + // FIXME: buffer full: pes packet is dropped + } + pes_index = 0; + } + } + + if (pes_index + size > pes_size) { + fprintf(stderr, "pip: pes buffer too small\n"); + // FIXME: error state + return; + } + memcpy(pes_buf + pes_index, data, size); + pes_index += size; +} + + /// Transport stream packet size +#define TS_PACKET_SIZE 188 + /// Transport stream packet sync byte +#define TS_PACKET_SYNC 0x47 + +/** +** Receive TS packet from device. +** +** @param data ts packet +** @param size size (#TS_PACKET_SIZE=188) of tes packet +*/ +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; + + if (p[0] != TS_PACKET_SYNC) { + esyslog(tr("tsdemux: transport stream out of sync\n")); + // FIXME: kill all buffers + return; + } + if (p[1] & 0x80) { // error indicatord + dsyslog("tsdemux: transport error\n"); + // FIXME: kill all buffers + goto next_packet; + } + if (0) { + int pid; + + pid = (p[1] & 0x1F) << 8 | p[2]; + fprintf(stderr, "tsdemux: PID: %#04x%s%s\n", pid, + p[1] & 0x40 ? " start" : "", p[3] & 0x10 ? " payload" : ""); + } + // skip adaptation field + switch (p[3] & 0x30) { // adaption field + case 0x00: // reserved + case 0x20: // adaptation field only + default: + goto next_packet; + case 0x10: // only payload + payload = 4; + break; + case 0x30: // skip adapation field + payload = 5 + p[4]; + // illegal length, ignore packet + if (payload >= TS_PACKET_SIZE) { + dsyslog("tsdemux: illegal adaption field length\n"); + goto next_packet; + } + break; + } + + PipPesParse(p + payload, TS_PACKET_SIZE - payload, p[1] & 0x40); + + next_packet: + p += TS_PACKET_SIZE; + size -= TS_PACKET_SIZE; + } +} + +////////////////////////////////////////////////////////////////////////////// + +/** +** Prepare new PIP. +*/ +static void NewPip(void) +{ + int channel_nr; + const cChannel *channel; + cDevice *device; + cSoftReceiver *receiver; + + if ((channel_nr = cDevice::CurrentChannel()) + && (channel = Channels.GetByNumber(cDevice::CurrentChannel())) + && (device = cDevice::GetDevice(channel, 1, false))) { + fprintf(stderr, "pip: %d %p %p\n", channel_nr, channel, device); + device->SwitchChannel(channel, false); + receiver = new cSoftReceiver(channel); + device->AttachReceiver(receiver); + fprintf(stderr, "pip: attached\n"); + } +} + +#endif + +////////////////////////////////////////////////////////////////////////////// // cOsdMenu ////////////////////////////////////////////////////////////////////////////// @@ -1192,8 +1387,8 @@ class cSoftHdMenu:public cOsdMenu int HotkeyCode; ///< current hot-key code void Create(void); ///< create plugin main menu public: - cSoftHdMenu(const char *, int = 0, int = 0, int = 0, int = 0, int = 0); - virtual ~ cSoftHdMenu(); + cSoftHdMenu(const char *, int = 0, int = 0, int = 0, int = 0, int = 0); + virtual ~ cSoftHdMenu(); virtual eOSState ProcessKey(eKeys); }; @@ -1213,12 +1408,16 @@ void cSoftHdMenu::Create(void) SetHasHotkeys(); Add(new cOsdItem(hk(tr("Suspend SoftHdDevice")), osUser1)); +#ifdef USE_PIP + Add(new cOsdItem(hk(tr("PIP")), osUser2)); +#endif Add(new cOsdItem(NULL, osUnknown, false)); Add(new cOsdItem(NULL, osUnknown, false)); GetStats(&missed, &duped, &dropped, &counter); - Add(new cOsdItem(cString:: - sprintf(tr(" Frames missed(%d) duped(%d) dropped(%d) total(%d)"), - missed, duped, dropped, counter), osUnknown, false)); + Add(new + cOsdItem(cString::sprintf(tr + (" Frames missed(%d) duped(%d) dropped(%d) total(%d)"), missed, + duped, dropped, counter), osUnknown, false)); SetCurrent(Get(current)); // restore selected menu entry Display(); // display build menu @@ -1408,6 +1607,11 @@ eOSState cSoftHdMenu::ProcessKey(eKeys key) } } return osEnd; +#ifdef USE_PIP + case osUser2: + NewPip(); + return osEnd; +#endif default: Create(); break; @@ -1707,8 +1911,8 @@ bool cSoftHdDevice::Flush(int timeout_ms) ** Sets the video display format to the given one (only useful if this ** device has an MPEG decoder). */ -void cSoftHdDevice:: -SetVideoDisplayFormat(eVideoDisplayFormat video_display_format) +void cSoftHdDevice:: SetVideoDisplayFormat(eVideoDisplayFormat + video_display_format) { dsyslog("[softhddev]%s: %d\n", __FUNCTION__, video_display_format); @@ -1826,6 +2030,11 @@ 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); } |