There is DVB-T broadcast in Cracow (
finally), so I started messing with TSD/PVR hardware

. Got some ideas:
1)
Recording multiple programs concurrently (from the same multiplex): we just need to set additional PIDs in PID filter bank/PID table.
TSD/PVR PID filter table: 32 hardware registers (128 bytes), starting at 0x30110100 address. E.g.:
Code: Select all
root@localhost:~/bin# reg-range-print 0x30110100 32
0x30110100: 0xA0CA
0x30110104: 0xA0CC
0x30110108: 0x9FFF
0x3011010C: 0x9FFF
0x30110110: 0x9FFF
0x30110114: 0xA000
0x30110118: 0xA010
0x3011011C: 0xA011
0x30110120: 0xA012
0x30110124: 0xA014
0x30110128: 0xA0C9
0x3011012C: 0xA0CD
0x30110130: 0x1FFF
0x30110134: 0x1FFF
0x30110138: 0x1FFF
0x3011013C: 0x1FFF
0x30110140: 0x1FFF
0x30110144: 0x1FFF
0x30110148: 0x0
0x3011014C: 0x0
0x30110150: 0x0
0x30110154: 0x0
0x30110158: 0x0
0x3011015C: 0x0
0x30110160: 0x0
0x30110164: 0x0
0x30110168: 0x0
0x3011016C: 0x0
0x30110170: 0x0
0x30110174: 0x0
0x30110178: 0x0
0x3011017C: 0x0
For each register/filter entry, bits [0-12] are actual PIDs.
Bits [3-13]: flags-switches, details unknown. Typically (I guess) 0x9E000/0x9A000 bitmask is used for PVR on, and 0xA000 for PVR off.
We can add extra PIDs to this table (unused entries == 0x0), like this:
Code: Select all
#!/bin/sh
# reg-range-print 0x30110100 32
## Polsat
devmem2 0x30110150 w 0xA065
devmem2 0x30110154 w 0xA066
devmem2 0x30110158 w 0xA067
## Polsat Sport News
devmem2 0x3011015C w 0xA321
devmem2 0x30110160 w 0xA322
devmem2 0x30110164 w 0xA323
## Tv Puls
devmem2 0x30110168 w 0xA191
devmem2 0x3011016C w 0xA192
devmem2 0x30110170 w 0xA193
## TVN
devmem2 0x30110174 w 0xA0C9
devmem2 0x30110178 w 0xA0CA
devmem2 0x3011017C w 0xA0CC
With such settings, it's possible to record up to 4 programs concurrently (bitrate ca 1.5-2.0 MB/s for SD channels, YMMV). It works much better while recording on network share. For unknown reasons, USB writes seem very slow, even for fast SSD SLC drive!
Generally (I don't know much about DVB-T/C), I think we need to add at least 3 PIDs per program (PMT, video, audio). E.g, PIDs for Polish MUX2 in Cracow:
Code: Select all
GP PID[s]
0x0000 (PAT), 0x1FFF (NULL)
0x0010, 0x0011, 0x0012, 0x0014: channel/network data, EPG, ...(???)
Programs (PMT PID, Video PID, Audio PID, ...)
1: Polsat 0x0065, 0x0066, 0x0067, 0x0069 (TTX ?)
2: Polsat Sport News 0x0321, 0x0322, 0x0323
3: PULS 2 0x0259, 0x025A, 0x025B
4: Tv Puls 0x0191, 0x0192, 0x0193
5: TV4 0x012D, 0x012E, 0x012F, 0x0131 (TTX ?)
6: TV6 0x02BD, 0x02BE, 0x02BF
7: TVN 0x00C9, 0x00CA, 0x00CC, 0x00CD (TTX ?)
8: TVN Siedem 0x01F5, 0x01F6, 0x01F8, 0x01F9 (TTX ?)
Individual programs can be extracted from recorded .ts file with TS Doctor.
Replacing entries 0 & 1 in PID filter table (while watching TV) results in funny/special effects: video from one program, audio from another one etc.

.
2)
Recording in the background: works for external sources (HDMI/PC/Component/...) with active PIP window, but not quite perfectly.. I guess we can improve it a little:
- PIP window can be hidden, by turning Chelsea scaler #1 off. It's possible from TDM. Probably doable from Content Library application level with simple SdVideo_Get()/SdVideo_Set() calls (not tested yet).
- audio not recorded for PIP Sound Select = MAIN: that's because audio PID is missing from filter table. I think it's easily remedied with 1) workaround.
reg-range-print.c (simple tool for figuring out register values / program PIDs):
Code: Select all
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/mman.h>
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
#define MAP_SIZE 0xB00000
int main(int argc, char **argv) {
int fd;
void *map_base, *virt_addr;
unsigned read_result, target;
int count=1;
if (argc < 2) {
fprintf(stderr, "Usage: %s addr [cnt]\n\taddr: register range (0x3000000-0x30B00000|0x0-0xCFFFFC)\n\tcnt: number of U32 registers to print\n", argv[0]);
exit(1);
}
target = strtoul(argv[1], 0, 0);
if (target >= 0x30000000 && target < 0x30B00000) target-=0x30000000;
if (target < 0 || target >= MAP_SIZE || target % 4) {
fprintf(stderr, "Error: invalid Address '0x%x'\n", target);
exit(1);
}
if (argc > 2) count=strtoul(argv[2], 0, 0);
if ((fd=open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
map_base=mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x30000000);
if (map_base == (void *) -1) FATAL;
int i=0; while (i < count) {
if ((target+4*i) >= MAP_SIZE) break;
virt_addr = map_base + target + 4*i;
read_result = *((unsigned long *) virt_addr);
printf("0x30%X: 0x%X\n", (target+4*i), read_result); fflush(stdout);
i++;
}
if (munmap(map_base, MAP_SIZE) == -1) FATAL;
close(fd);
return 0;
}