[mythtv] [patch] hdtvrecorder and pat/pmt parsing

Steve Brown sbrown at cortland.com
Fri Dec 5 17:08:55 EST 2003


Two steps forward, one back.

Attached is yet another updated patch that handles the case where the
program number, if not specified, defaulted to 0. Some PAT's have one of 
the psip pids as program 0. The program number now defaults to program #1.

I sure would like somebody to try this. I mentioned it on the pchdtv 
forum, but it's pretty lonely over there. Maybe a msg every few days.

There are still some problems in the ffmpeg code.  If a channel or 
programming change causes the format to change, like from 1280x720p to 
1920x1080i, the stream gets badly broken and causes xvmcvideo to give up 
and exit. Escape and play fix it.

Steve





-------------- next part --------------
Index: libs/libmythtv/channel.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/channel.cpp,v
retrieving revision 1.57
diff -u -r1.57 channel.cpp
--- libs/libmythtv/channel.cpp	5 Dec 2003 01:05:35 -0000	1.57
+++ libs/libmythtv/channel.cpp	5 Dec 2003 21:39:10 -0000
@@ -341,6 +341,8 @@
     int finetune = query.value(0).toInt();
     QString freqid = query.value(1).toString();
     QString tvformat = query.value(2).toString();
+    VERBOSE(VB_CHANNEL,QString("Changed to channel:%1 freqid:%2 finetune:%3")\
+        .arg(chan).arg(freqid).arg(finetune));
 
     pthread_mutex_unlock(&db_lock);
 
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	5 Dec 2003 21:39:10 -0000
@@ -95,10 +95,11 @@
 
     firstgoppos = 0;
 
-    desired_program = 0;
+    desired_program = 1; // default to program #1
     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
@@ -521,17 +512,24 @@
         return false;  // premature end of packet
     pos += 2 + (((buffer[pos] << 8) | buffer[pos+1]) & 0x0fff);
 
+    video_pid = audio_pid = -1;
     // rewrite other pids
     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 < 0)) {
+            audio_pid = pid;
             pid = AUDIO_PID(new_pid);
         }
 
@@ -545,6 +543,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 +620,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 +687,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 +737,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 +750,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 +760,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 +768,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 +779,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 +796,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,8 +877,7 @@
 void HDTVRecorder::ChannelNameChanged(const QString& new_chan)
 {
     RecorderBase::ChannelNameChanged(new_chan);
-
-    desired_program = 0;
+//cerr << __FUNCTION__ << " new_chan:" << new_chan << endl;
     // look up freqid
     pthread_mutex_lock(db_lock);
     QString thequery = QString("SELECT freqid "
@@ -896,7 +896,8 @@
     pthread_mutex_unlock(db_lock);
     int pos = freqid.find('-');
     if (pos != -1) 
-    {
         desired_program = atoi(freqid.mid(pos+1).ascii());
-    }
+    else
+        desired_program = 1;// default to program #1
+//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	5 Dec 2003 21:39:10 -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