[mythtv] [patch] hdtvrecorder and pat/pmt parsing
Steve Brown
sbrown at cortland.com
Wed Dec 3 17:53:53 EST 2003
Rather than parsing the pat and pmt, hdtvrecorder assumed that the pmt
pid was 1 less than the lowest pid found in the first 50 ts packets.
This usually works.
However, it broke for KING-HD here in Seattle, where the pmt is 0x30 and
the video/audio pids are 0x11 and 0x14 respectively. The symptom is an
"avformat error -1" from avformatdecoder.cpp.
The attached patch now plays all my local hd stations. Other
prebuffering and osd update hiccups are unaffected.
I'd appreciate some confirmation that I haven't busted something in the
process.
The patch is against the current cvs.
Steve
-------------- next part --------------
Index: libs/libmythtv/hdtvrecorder.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/hdtvrecorder.cpp,v
retrieving revision 1.11
diff -u -r1.11 hdtvrecorder.cpp
--- libs/libmythtv/hdtvrecorder.cpp 16 Nov 2003 19:08:33 -0000 1.11
+++ libs/libmythtv/hdtvrecorder.cpp 3 Dec 2003 22:06:24 -0000
@@ -98,7 +98,8 @@
desired_program = 0;
pat_pid = 0;
psip_pid = 0x1ffb;
- base_pid = 0; // will be filled in when we find it
+ audio_pid = video_pid = -1;
+ pmt_pid = -1;
output_base_pid = 0;
ts_packets = 0; // cumulative packet count
@@ -456,6 +457,10 @@
return false; // new packet would exceed boundary, skip it
pos = 8; // section header is 8 bytes, skip it
+//fprintf(stderr, "%s: old:0x%0x 0x%0x new: 0x0001 0x%0x\n",
+// __FUNCTION__, (buffer[pos] << 8) | buffer[pos + 1],
+// (buffer[pos + 2] << 8) | buffer[pos + 3],
+// pid);
buffer[pos] = 0x00;
buffer[pos+1] = 0x01;
@@ -481,8 +486,7 @@
return true;
}
-bool HDTVRecorder::RewritePMT(unsigned char *buffer, int old_pid, int new_pid,
- int pkt_len)
+bool HDTVRecorder::RewritePMT(unsigned char *buffer, int new_pid, int pkt_len)
{
// TODO: if it's possible for a PMT to span packets, then this function
// doesn't know how to deal with anything after the first packet. On the
@@ -492,6 +496,7 @@
int pid;
int sec_len = ((buffer[1] & 0x0f) << 8) + buffer[2];
sec_len += 3; // adjust for 3 header bytes
+//fprintf(stderr, "%s: new_pid:0x%0x\n", __FUNCTION__, new_pid);
// make sure section doesn't span packet bounds
if (sec_len > pkt_len)
@@ -500,20 +505,6 @@
// rewrite program number to 1
buffer[3] = 0x00;
buffer[4] = 0x01;
-
- // rewrite pcr_pid
- pid = ((buffer[pos] << 8) | buffer[pos+1]) & 0x1fff;
- if (pid == VIDEO_PID(old_pid)) {
- pid = VIDEO_PID(new_pid);
- }
- else if (pid == AUDIO_PID(old_pid)) {
- pid = AUDIO_PID(new_pid);
- }
- else {
- return false; // don't know how to rewrite
- }
- buffer[pos] = ((pid & 0x1f00) >> 8) | 0xe0;
- buffer[pos+1] = pid & 0x00ff;
pos += 2;
// skip program info
@@ -525,13 +516,19 @@
while (pos < sec_len - 4) {
if (buffer[pos] == 0xff)
break; // hit end of packet, ok here
+ int stream_type = (int)buffer[pos];
+//cerr << __FUNCTION__ << " stream_type:0x" << hex << stream_type << dec << endl;
+
pos++;
pid = ((buffer[pos] << 8) | buffer[pos+1]) & 0x1fff;
- if (pid == VIDEO_PID(old_pid)) {
+
+ if (stream_type == 0x02) {
+ video_pid = pid;
pid = VIDEO_PID(new_pid);
- }
- else if (pid == AUDIO_PID(old_pid)) {
+ }
+ else if (stream_type == 0x81 | stream_type == 0x04) {
+ audio_pid = pid;
pid = AUDIO_PID(new_pid);
}
@@ -545,6 +542,20 @@
pos += 2 + (((buffer[pos] << 8) | buffer[pos+1]) & 0x0fff);
}
+ // rewrite pcr_pid
+ pid = ((buffer[8] << 8) | buffer[9]) & 0x1fff;
+ if (pid == video_pid) {
+ pid = VIDEO_PID(new_pid);
+ }
+ else if (pid == audio_pid) {
+ pid = AUDIO_PID(new_pid);
+ }
+ else {
+ return false; // don't know how to rewrite
+ }
+ buffer[8] = ((pid & 0x1f00) >> 8) | 0xe0;
+ buffer[9] = pid & 0x00ff;
+
// fix the checksum
unsigned int crc = mpegts_crc32(buffer, sec_len - 4);
buffer[sec_len - 4] = (crc & 0xff000000) >> 24;
@@ -608,7 +619,7 @@
}
payload_unit_start_indicator = (get1bit(buffer[pos], 1));
pid = ((buffer[pos] << 8) + buffer[pos+1]) & 0x1fff;
- //cerr << "found PID " << pid << endl;
+ //cerr << "found PID 0x" << hex << pid << dec << endl;
pos += 2;
if (get1bit(buffer[pos], 1))
{
@@ -675,22 +686,43 @@
// PIDs we are looking for, and can thus "tune" the
// subprogram more quickly.
- // For now we're using the dirty hack below instead.
-
- // We should rewrite the PAT to describe just the one
+ // We rewrite the PAT to describe just the one
// stream we are recording. Always use the same set of
// PIDs so the decoder has an easier time following
// channel changes.
- if (base_pid) {
- // sec_start should pretty much always be pos + 1, but
- // just in case...
- int sec_start = pos + buffer[pos] + 1;
-
- // write to ringbuffer if pids gets rewritten successfully.
- if (RewritePAT(&buffer[sec_start], output_base_pid,
- packet_end_pos - sec_start))
- ringBuffer->Write(&buffer[packet_start_pos], 188);
+ //
+ // Basically, the output PMT is pid 0x10, video is 0x11 and
+ // audio is 0x14.
+ //
+ // sec_start should pretty much always be pos + 1, but
+ // just in case...
+ int sec_start = pos + buffer[pos] + 1;
+ int sec_len = (buffer[sec_start + 1] & 0x0f) << 8 | buffer[sec_start + 2];
+ int i;
+//cerr << __FUNCTION__ << " desired_program:" << desired_program
+// << " table_id:0x" << hex << (int)buffer[sec_start] << dec
+// << " sec_len:" << sec_len << endl;
+ pmt_pid = -1;
+ for (i = sec_start + 8; i < sec_start + 3 + sec_len - 4; i += 4) {
+ int prog_num = (buffer[i] << 8) | buffer[i + 1];
+ int prog_pid = (buffer[i + 2] & 0x0e) << 8 | buffer[i + 3];
+ if (prog_num == desired_program) {
+ pmt_pid = prog_pid;
+ break;
+ }
}
+ if (pmt_pid == -1) {
+ pmt_pid = (buffer[sec_start + 8 + 2] & 0x0e) << 8 |
+ buffer[sec_start + 8 + 3];
+ cerr << __FUNCTION__ << " no match for desired program"
+ << " using first program in PAT" << endl;
+ }
+ output_base_pid = 16;
+
+ // write to ringbuffer if pids gets rewritten successfully.
+ if (RewritePAT(&buffer[sec_start], output_base_pid,
+ packet_end_pos - sec_start))
+ ringBuffer->Write(&buffer[packet_start_pos], 188);
}
else if (pid == psip_pid)
{
@@ -704,7 +736,7 @@
// downloaded XMLTV data.
}
- else if (pid == VIDEO_PID(base_pid))
+ else if (pid == video_pid)
{
FindKeyframes(buffer, packet_start_pos, pos,
adaptation_field_control, payload_unit_start_indicator);
@@ -717,7 +749,7 @@
ringBuffer->Write(&buffer[packet_start_pos], 188);
}
}
- else if (pid == AUDIO_PID(base_pid))
+ else if (pid == audio_pid)
{
// decoder needs audio, of course (just this PID)
if (gopset || firstgoppos)
@@ -727,7 +759,7 @@
ringBuffer->Write(&buffer[packet_start_pos], 188);
}
}
- else if (pid == base_pid)
+ else if (pid == pmt_pid)
{
// decoder needs base PID
int sec_start = pos + buffer[pos] + 1;
@@ -735,7 +767,7 @@
// if it's a PMT table, rewrite the PIDs contained in it too
if (buffer[sec_start] == 0x02) {
- if (RewritePMT(&(buffer[sec_start]), base_pid, output_base_pid,
+ if (RewritePMT(&(buffer[sec_start]), output_base_pid,
packet_end_pos - sec_start))
{
ringBuffer->Write(&buffer[packet_start_pos], 188);
@@ -746,39 +778,6 @@
ringBuffer->Write(&buffer[packet_start_pos], 188);
}
}
- else
- {
- // Not a PID we're watching
-
- // As a hack until we start decoding PAT, find the lowest
- // video PID in the first 50 packets and record only that
- // stream
- if ((pid & 0xff0f) == 0x0001 && !base_pid)
- {
- // Look for our desired subprogram here to ensure we're
- // actually seeing packets from it... if not, we'll
- // fall back on the 1st one.
- int program_num = (pid & 0x00f0) >> 4;
- if (program_num == desired_program && desired_program != 0)
- {
- base_pid = pid - 1;
- if (output_base_pid == 0)
- output_base_pid = 16;
- }
- else
- {
- if (pid < lowest_video_pid)
- lowest_video_pid = pid;
- video_pid_packets++;
- if (video_pid_packets >= 50)
- {
- base_pid = lowest_video_pid - 1;
- if (output_base_pid == 0)
- output_base_pid = 0x10;
- }
- }
- }
- }
// Advance to next TS packet
pos = packet_end_pos;
}
@@ -796,8 +795,9 @@
framesWritten = 0;
gopset = false;
firstgoppos = 0;
- base_pid = 0;
ts_packets = 0;
+ pmt_pid = -1;
+ video_pid = audio_pid = -1;
lowest_video_pid = 0x1fff;
video_pid_packets = 0;
@@ -876,7 +876,7 @@
void HDTVRecorder::ChannelNameChanged(const QString& new_chan)
{
RecorderBase::ChannelNameChanged(new_chan);
-
+//cerr << __FUNCTION__ << " new_chan:" << new_chan << endl;
desired_program = 0;
// look up freqid
pthread_mutex_lock(db_lock);
@@ -899,4 +899,5 @@
{
desired_program = atoi(freqid.mid(pos+1).ascii());
}
+//cerr << __FUNCTION__ << " curChannelName:" << curChannelName << " desired_program:" << desired_program << endl;
}
Index: libs/libmythtv/hdtvrecorder.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/hdtvrecorder.h,v
retrieving revision 1.9
diff -u -r1.9 hdtvrecorder.h
--- libs/libmythtv/hdtvrecorder.h 16 Nov 2003 19:08:33 -0000 1.9
+++ libs/libmythtv/hdtvrecorder.h 3 Dec 2003 22:06:24 -0000
@@ -51,8 +51,7 @@
int ResyncStream(unsigned char *buffer, int curr_pos, int len);
void RewritePID(unsigned char *buffer, int pid);
bool RewritePAT(unsigned char *buffer, int pid, int pkt_len);
- bool RewritePMT(unsigned char *buffer, int old_pid, int new_pid,
- int pkt_len);
+ bool RewritePMT(unsigned char *buffer, int new_pid, int pkt_len);
bool recording;
bool encoding;
@@ -77,8 +76,10 @@
int desired_program;
int pat_pid;
+ int pmt_pid;
+ int video_pid;
+ int audio_pid;
int psip_pid;
- int base_pid;
int output_base_pid;
int ts_packets;
More information about the mythtv-dev
mailing list