diff -urN astra.orig/modules/mpegts/mpegts.h astra/modules/mpegts/mpegts.h
--- astra.orig/modules/mpegts/mpegts.h	2015-11-12 12:48:51.000000000 +0300
+++ astra/modules/mpegts/mpegts.h	2015-11-12 12:51:45.043722024 +0300
@@ -98,6 +98,7 @@
     MPEGTS_PACKET_VIDEO     = MPEGTS_PACKET_PES | 0x01,
     MPEGTS_PACKET_AUDIO     = MPEGTS_PACKET_PES | 0x02,
     MPEGTS_PACKET_SUB       = MPEGTS_PACKET_PES | 0x04,
+    MPEGTS_PACKET_PCR       = MPEGTS_PACKET_PES | 0x08,
     MPEGTS_PACKET_DATA      = 0x01000000,
     MPEGTS_PACKET_NULL      = 0x02000000
 } mpegts_packet_type_t;
diff -urN astra.orig/modules/pcrgen/module.mk astra/modules/pcrgen/module.mk
--- astra.orig/modules/pcrgen/module.mk	1970-01-01 03:00:00.000000000 +0300
+++ astra/modules/pcrgen/module.mk	2015-11-12 12:49:44.000000000 +0300
@@ -0,0 +1,2 @@
+SOURCES="pcrgen.c"
+MODULES="pcrgen"
diff -urN astra.orig/modules/pcrgen/pcrgen.c astra/modules/pcrgen/pcrgen.c
--- astra.orig/modules/pcrgen/pcrgen.c	1970-01-01 03:00:00.000000000 +0300
+++ astra/modules/pcrgen/pcrgen.c	2015-11-13 14:47:44.136436852 +0300
@@ -0,0 +1,506 @@
+/*
+ * Astra Module: pcrgen
+ * http://cesbo.com/astra
+ *
+ * Copyright (C) 2014-2015, Konstantin Kuzov <master.nosferatu@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <astra.h>
+
+#define MSG(_msg) "[pcrgen %s] " _msg, mod->config.name
+
+struct module_data_t
+{
+    MODULE_STREAM_DATA();
+
+    /* Options */
+    struct
+    {
+        const char *name;
+        int pnr;
+        int pcr_pid;
+        int pcr_mode;
+        int pcr_offset;
+        int pcr_interval;
+        int pcr_pcrpid;
+        bool no_reload;
+    } config;
+
+    uint8_t custom_ts[TS_PACKET_SIZE];
+
+    mpegts_psi_t *pat;
+    mpegts_psi_t *pmt;
+
+    mpegts_packet_type_t stream[MAX_PID];
+    mpegts_pes_t *pes[MAX_PID];
+
+    mpegts_psi_t *custom_pat;
+    mpegts_psi_t *custom_pmt;
+
+    uint8_t pcr_cc;
+    uint16_t tsid;
+
+    uint8_t pat_version;
+
+    asc_timer_t *pcr_timer;
+    uint64_t pes_time;
+};
+
+/*
+ * oooo     oooo  ooooooo  ooooooooo  ooooo  oooo ooooo       ooooooooooo
+ *  8888o   888 o888   888o 888    88o 888    88   888         888    88
+ *  88 888o8 88 888     888 888    888 888    88   888         888ooo8
+ *  88  888  88 888o   o888 888    888 888    88   888      o  888    oo
+ * o88o  8  o88o  88ooo88  o888ooo88    888oo88   o888ooooo88 o888ooo8888
+ *
+ */
+
+static void stream_reload(module_data_t *mod)
+{
+    memset(mod->stream, 0, sizeof(mod->stream));
+
+    for(int __i = 0; __i < MAX_PID; ++__i)
+    {
+        if(mod->__stream.pid_list[__i])
+            module_stream_demux_leave_pid(mod, __i);
+
+        if(mod->pes[__i])
+            mpegts_pes_destroy(mod->pes[__i]);
+    }
+
+    mod->pat->crc32 = 0;
+    mod->pmt->crc32 = 0;
+
+    mod->stream[0x00] = MPEGTS_PACKET_PAT;
+    module_stream_demux_join_pid(mod, 0x00);
+
+    mod->stream[0x01] = MPEGTS_PACKET_CAT;
+    module_stream_demux_join_pid(mod, 0x01);
+
+    mod->stream[0x11] = MPEGTS_PACKET_SDT;
+    module_stream_demux_join_pid(mod, 0x11);
+
+    mod->stream[0x12] = MPEGTS_PACKET_EIT;
+    module_stream_demux_join_pid(mod, 0x12);
+
+    mod->stream[0x14] = MPEGTS_PACKET_TDT;
+    module_stream_demux_join_pid(mod, 0x14);
+}
+
+
+/*
+ * oooooooooo   o   ooooooooooo
+ *  888    888 888  88  888  88
+ *  888oooo88 8  88     888
+ *  888      8oooo88    888
+ * o888o   o88o  o888o o888o
+ *
+ */
+
+static void on_pat(void *arg, mpegts_psi_t *psi)
+{
+    module_data_t *mod = (module_data_t *)arg;
+
+    if(psi->buffer[0] != 0x00)
+        return;
+
+    // check changes
+    const uint32_t crc32 = PSI_GET_CRC32(psi);
+    if(crc32 == psi->crc32)
+    {
+        mpegts_psi_demux(mod->custom_pat, (ts_callback_t)__module_stream_send, &mod->__stream);
+        return;
+    }
+
+    // check crc
+    if(crc32 != PSI_CALC_CRC32(psi))
+    {
+        asc_log_error(MSG("PAT checksum error"));
+        return;
+    }
+
+    // reload stream
+    if(psi->crc32 != 0)
+    {
+        asc_log_warning(MSG("PAT changed. Reload stream info"));
+        stream_reload(mod);
+    }
+
+    psi->crc32 = crc32;
+
+    mod->tsid = PAT_GET_TSID(psi);
+
+    const uint8_t *pointer;
+
+    PAT_ITEMS_FOREACH(psi, pointer)
+    {
+        const uint16_t pnr = PAT_ITEM_GET_PNR(psi, pointer);
+        if(!pnr)
+            continue;
+
+        if(!mod->config.pnr)
+            mod->config.pnr = pnr;
+
+        if(pnr == mod->config.pnr)
+        {
+            const uint16_t pid = PAT_ITEM_GET_PID(psi, pointer);
+            mod->stream[pid] = MPEGTS_PACKET_PMT;
+            module_stream_demux_join_pid(mod, pid);
+            mod->pmt->pid = pid;
+            mod->pmt->crc32 = 0;
+            break;
+        }
+    }
+
+    if(PAT_ITEMS_EOL(psi, pointer))
+    {
+        mod->custom_pat->buffer_size = 0;
+        asc_log_error(MSG("PAT: stream with id %d is not found"), mod->config.pnr);
+        return;
+    }
+
+    const uint8_t pat_version = PAT_GET_VERSION(mod->custom_pat) + 1;
+    PAT_INIT(mod->custom_pat, mod->tsid, pat_version);
+    memcpy(PAT_ITEMS_FIRST(mod->custom_pat), pointer, 4);
+
+    mod->custom_pmt->pid = mod->pmt->pid;
+
+    mod->pat_version = (mod->pat_version + 1) & 0x0F;
+    PAT_SET_VERSION(mod->custom_pat, mod->pat_version);
+
+    mod->custom_pat->buffer_size = 8 + 4 + CRC32_SIZE;
+    PSI_SET_SIZE(mod->custom_pat);
+    PSI_SET_CRC32(mod->custom_pat);
+
+    mpegts_psi_demux(mod->custom_pat, (ts_callback_t)__module_stream_send, &mod->__stream);
+
+    if(mod->config.no_reload)
+        mod->stream[psi->pid] = MPEGTS_PACKET_UNKNOWN;
+}
+
+/*
+ * oooooooooo oooo     oooo ooooooooooo
+ *  888    888 8888o   888  88  888  88
+ *  888oooo88  88 888o8 88      888
+ *  888        88  888  88      888
+ * o888o      o88o  8  o88o    o888o
+ *
+ */
+
+static void on_pmt(void *arg, mpegts_psi_t *psi)
+{
+    module_data_t *mod = (module_data_t *)arg;
+
+    if(psi->buffer[0] != 0x02)
+        return;
+
+    // check pnr
+    const uint16_t pnr = PMT_GET_PNR(psi);
+    if(pnr != mod->config.pnr)
+        return;
+
+    // check changes
+    const uint32_t crc32 = PSI_GET_CRC32(psi);
+    if(crc32 == psi->crc32)
+    {
+        mpegts_psi_demux(mod->custom_pmt, (ts_callback_t)__module_stream_send, &mod->__stream);
+        return;
+    }
+
+    // check crc
+    if(crc32 != PSI_CALC_CRC32(psi))
+    {
+        asc_log_error(MSG("PMT checksum error"));
+        return;
+    }
+
+    // reload stream
+    if(psi->crc32 != 0)
+    {
+        asc_log_warning(MSG("PMT changed. Reload stream info"));
+        stream_reload(mod);
+        return;
+    }
+
+    psi->crc32 = crc32;
+
+    uint16_t skip = 12;
+    memcpy(mod->custom_pmt->buffer, psi->buffer, 10);
+
+    const uint16_t pcr_pid = PMT_GET_PCR(psi);
+    bool join_pcr = true;
+
+    const uint8_t *desc_pointer;
+
+    PMT_DESC_FOREACH(psi, desc_pointer)
+    {
+        if(desc_pointer[0] == 0x09)
+        {
+            const uint16_t ca_pid = DESC_CA_PID(desc_pointer);
+
+            if(mod->stream[ca_pid] == MPEGTS_PACKET_UNKNOWN && ca_pid != NULL_TS_PID)
+            {
+                mod->stream[ca_pid] = MPEGTS_PACKET_CA;
+                module_stream_demux_join_pid(mod, ca_pid);
+            }
+        }
+
+        const uint8_t size = desc_pointer[1] + 2;
+        memcpy(&mod->custom_pmt->buffer[skip], desc_pointer, size);
+        skip += size;
+    }
+
+    {
+        const uint16_t size = skip - 12; // 12 - PMT header
+        mod->custom_pmt->buffer[10] = (psi->buffer[10] & 0xF0) | ((size >> 8) & 0x0F);
+        mod->custom_pmt->buffer[11] = (size & 0xFF);
+    }
+
+    const uint8_t *pointer;
+    PMT_ITEMS_FOREACH(psi, pointer)
+    {
+        const uint16_t pid = PMT_ITEM_GET_PID(psi, pointer);
+
+        PMT_ITEM_DESC_FOREACH(pointer, desc_pointer)
+        {
+            const uint8_t desc_type = desc_pointer[0];
+
+            if(desc_type == 0x09)
+            {
+                const uint16_t ca_pid = DESC_CA_PID(desc_pointer);
+
+                if(mod->stream[ca_pid] == MPEGTS_PACKET_UNKNOWN && ca_pid != NULL_TS_PID)
+                {
+                    mod->stream[ca_pid] = MPEGTS_PACKET_CA;
+                    module_stream_demux_join_pid(mod, ca_pid);
+                }
+            }
+        }
+
+        const uint16_t skip_last = skip;
+
+        memcpy(&mod->custom_pmt->buffer[skip], pointer, 5);
+        skip += 5;
+
+        mod->stream[pid] = MPEGTS_PACKET_PES;
+        mod->pes[pid] = mpegts_pes_init(MPEGTS_PACKET_DATA, pid, 0);
+        module_stream_demux_join_pid(mod, pid);
+
+        if(pid == pcr_pid)
+            join_pcr = false;
+
+        PMT_ITEM_DESC_FOREACH(pointer, desc_pointer)
+        {
+            if(desc_pointer[0] == 0x09)
+            {
+                const uint16_t ca_pid = DESC_CA_PID(desc_pointer);
+
+                if(mod->stream[ca_pid] == MPEGTS_PACKET_UNKNOWN && ca_pid != NULL_TS_PID)
+                {
+                    mod->stream[ca_pid] = MPEGTS_PACKET_CA;
+                    module_stream_demux_join_pid(mod, ca_pid);
+                }
+            }
+
+            const uint8_t size = desc_pointer[1] + 2;
+            memcpy(&mod->custom_pmt->buffer[skip], desc_pointer, size);
+            skip += size;
+        }
+
+        const uint16_t size = skip - skip_last - 5;
+        mod->custom_pmt->buffer[skip_last + 3] = (size << 8) & 0x0F;
+        mod->custom_pmt->buffer[skip_last + 4] = (size & 0xFF);
+    }
+
+    mod->custom_pmt->buffer_size = skip + CRC32_SIZE;
+
+    if(join_pcr)
+    {
+        mod->stream[pcr_pid] = MPEGTS_PACKET_PES;
+        module_stream_demux_join_pid(mod, pcr_pid);
+    }
+
+    if (mod->config.pcr_pid)
+    {
+        if (!mod->config.pcr_mode)
+            mod->stream[pcr_pid] = MPEGTS_PACKET_PCR;
+
+        PMT_SET_PCR(mod->custom_pmt, mod->config.pcr_pid);
+    }
+
+    PSI_SET_SIZE(mod->custom_pmt);
+    PSI_SET_CRC32(mod->custom_pmt);
+    mpegts_psi_demux(mod->custom_pmt, (ts_callback_t)__module_stream_send, &mod->__stream);
+
+    if(mod->config.no_reload)
+        mod->stream[psi->pid] = MPEGTS_PACKET_UNKNOWN;
+}
+
+static void on_pes(void *arg, mpegts_pes_t *pes)
+{
+    module_data_t *mod = arg;
+
+    uint64_t pes_time = PES_GET_PTS(pes) << 9;
+
+    if (pes_time + mod->config.pcr_offset > mod->pes_time)
+        mod->pes_time = pes_time + mod->config.pcr_offset;
+}
+
+static void on_pcr_timer(void *arg)
+{
+    module_data_t *mod = arg;
+
+    if (mod->pes_time > 0)
+    {
+        mod->pcr_cc++;
+        if (mod->pcr_cc > 15)
+            mod->pcr_cc = 0;
+
+        mod->custom_ts[0] = 0x47;
+        mod->custom_ts[1] = (mod->config.pcr_pid << 8) & 0x0F;
+        mod->custom_ts[2] = (mod->config.pcr_pid & 0xFF);
+        mod->custom_ts[3] = mod->pcr_cc + 0x20;
+        mod->custom_ts[4] = 0x07;
+        mod->custom_ts[5] = 1 << 4;
+
+        mod->custom_ts[6] = (mod->pes_time >> 34 ) & 0xff;
+        mod->custom_ts[7] = (mod->pes_time >> 26 ) & 0xff;
+        mod->custom_ts[8] = (mod->pes_time >> 18 ) & 0xff;
+        mod->custom_ts[9] = (mod->pes_time >> 10 ) & 0xff;
+        mod->custom_ts[10] = 0x7e | ( ( mod->pes_time & (1<<9) ) >> 2 ) | ( ( mod->pes_time & (1<<8) ) >> 8 );
+        mod->custom_ts[11] = mod->pes_time & 0xff;
+
+        memset(&mod->custom_ts[TS_HEADER_SIZE + mod->custom_ts[4] + 1], 0xFF, TS_BODY_SIZE - mod->custom_ts[4] - 1);
+        TS_SET_PID(mod->custom_ts, mod->config.pcr_pid);
+        module_stream_send(mod, mod->custom_ts);
+    }
+}
+
+static void on_ts(module_data_t *mod, const uint8_t *ts)
+{
+    const uint16_t pid = TS_GET_PID(ts);
+    if(!module_stream_demux_check_pid(mod, pid))
+        return;
+
+    if(pid == NULL_TS_PID)
+        return;
+
+    switch(mod->stream[pid])
+    {
+        case MPEGTS_PACKET_PCR:
+            if (mod->config.pcr_pid && mod->config.pcr_mode == 0)
+            {
+                if (TS_IS_PCR(ts))
+                {
+                    memcpy(mod->custom_ts, ts, TS_PACKET_SIZE);
+
+                    mod->pcr_cc++;
+                    if (mod->pcr_cc > 15)
+                        mod->pcr_cc = 0;
+
+                    mod->custom_ts[3] = mod->pcr_cc + (mod->custom_ts[3] & 0xc0) + 0x20;
+
+                    uint8_t aflen = mod->custom_ts[4];
+                    if (aflen > 0 && aflen < TS_BODY_SIZE)
+                    {
+                        memset(&mod->custom_ts[TS_HEADER_SIZE + aflen + 1], 0xFF, TS_BODY_SIZE - aflen - 1);
+                        TS_SET_PID(mod->custom_ts, mod->config.pcr_pid);
+                        module_stream_send(mod, mod->custom_ts);
+                    }
+                }
+            }
+            break;
+        case MPEGTS_PACKET_CAT:
+        case MPEGTS_PACKET_SDT:
+        case MPEGTS_PACKET_EIT:
+        case MPEGTS_PACKET_DATA:
+            break;
+        case MPEGTS_PACKET_PAT:
+            mpegts_psi_mux(mod->pat, ts, on_pat, mod);
+            return;
+        case MPEGTS_PACKET_PMT:
+            mpegts_psi_mux(mod->pmt, ts, on_pmt, mod);
+            return;
+        case MPEGTS_PACKET_PES:
+            if (mod->config.pcr_pcrpid == 0 || pid == mod->config.pcr_pcrpid)
+                mpegts_pes_mux(mod->pes[pid], ts, on_pes, mod);
+            break;
+        case MPEGTS_PACKET_UNKNOWN:
+            return;
+        default:
+            break;
+    }
+
+    module_stream_send(mod, ts);
+}
+
+
+static void module_init(module_data_t *mod)
+{
+    module_stream_init(mod, on_ts);
+    module_stream_demux_set(mod, NULL, NULL);
+
+    module_option_string("name", &mod->config.name, NULL);
+    asc_assert(mod->config.name != NULL, "[pcr] option 'name' is required");
+
+    module_option_number("pcrgen", &mod->config.pcr_pid);
+    asc_assert(mod->config.pcr_pid != 0, "[pcr] option 'pcrgen' is required");
+
+    module_option_number("pcrgen_mode", &mod->config.pcr_mode);
+    module_option_number("pcrgen_offset", &mod->config.pcr_offset);
+    module_option_number("pcrgen_interval", &mod->config.pcr_interval);
+    module_option_number("pcrgen_pid", &mod->config.pcr_pcrpid);
+    if (mod->config.pcr_interval < 50)
+        mod->config.pcr_interval = 50;
+
+    module_option_number("pnr", &mod->config.pnr);
+    
+    mod->pat = mpegts_psi_init(MPEGTS_PACKET_PAT, 0);
+    mod->pmt = mpegts_psi_init(MPEGTS_PACKET_PMT, MAX_PID);
+    mod->custom_pat = mpegts_psi_init(MPEGTS_PACKET_PAT, 0);
+    mod->custom_pmt = mpegts_psi_init(MPEGTS_PACKET_PMT, MAX_PID);
+    mod->stream[0] = MPEGTS_PACKET_PAT;
+    module_stream_demux_join_pid(mod, 0);
+
+    if (mod->config.pcr_mode)
+        mod->pcr_timer = asc_timer_init(mod->config.pcr_interval, on_pcr_timer, mod);
+}
+
+static void module_destroy(module_data_t *mod)
+{
+    module_stream_destroy(mod);
+
+    mpegts_psi_destroy(mod->pat);
+    mpegts_psi_destroy(mod->pmt);
+    mpegts_psi_destroy(mod->custom_pat);
+    mpegts_psi_destroy(mod->custom_pmt);
+
+    for(int i = 0; i < MAX_PID; ++i)
+    {
+        if(mod->pes[i])
+            mpegts_pes_destroy(mod->pes[i]);
+    }
+
+    if(mod->pcr_timer)
+        asc_timer_destroy(mod->pcr_timer);
+}
+
+MODULE_STREAM_METHODS()
+MODULE_LUA_METHODS()
+{
+    MODULE_STREAM_METHODS_REF()
+};
+MODULE_LUA_REGISTER(pcrgen)
diff -urN astra.orig/scripts/base.lua astra/scripts/base.lua
--- astra.orig/scripts/base.lua	2015-11-12 12:48:51.000000000 +0300
+++ astra/scripts/base.lua	2015-11-13 14:48:12.203277648 +0300
@@ -280,6 +280,7 @@
             if conf.map then return true end
             if conf.filter then return true end
             if conf["filter~"] then return true end
+            if conf.pcrgen then return true end
             return false
         end
         if check_dependent() then conf.pnr = 0 end
@@ -288,6 +289,21 @@
     if conf.pnr ~= nil then
         if conf.cam and conf.cam ~= true then conf.cas = true end
 
+        if conf.pcrgen ~= nil then
+            instance.pcr = pcrgen({
+                upstream = instance.tail:stream(),
+                name = conf.name,
+                pnr = conf.pnr,
+                pcrgen = conf.pcrgen,
+                pcrgen_mode = conf.pcrgen_mode,
+                pcrgen_offset = conf.pcrgen_offset,
+                pcrgen_interval = conf.pcrgen_interval,
+                pcrgen_pid = conf.pcrgen_pid
+            })
+
+            instance.tail = instance.pcr;
+        end
+
         instance.channel = channel({
             upstream = instance.tail:stream(),
             name = conf.name,
