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

Steve Brown sbrown at cortland.com
Fri Dec 5 11:09:46 EST 2003


Doug Larrick wrote:

> I'm a little concerned about what happens in RewritePMT when a program  
> has multiple audio PIDs associated with it, e.g. a second audio  
> program.  I think it will probably latch onto the last one in the  
> table, which probably *is* the Spanish, French, or descriptive audio  
> program.
> Instead of setting video_pid and audio_pid in RewritePMT, can you  
> decode them out of the PAT when you find the desired_program (where you  
> currently set the pmt_pid), choosing the first audio PID?
> 
> 

Doug,

I think the attached patch addresses your concern.

When I get a chance, I'll look at the dvb code and see how Kenneth 
handles multiple audio channels per mux.

The hdtv channels don't broadcast 24x7 up here. It sure would be nice if 
mythfrontend recovered from no backend data. Especially with the flakey 
behavior of the Nvidia xvmc driver. FWIW, there was some discussion 
about this on the nvidia board. The problem is well known, but it seems 
like the maintainers were still trying to figure out whether this was a 
bug or feature. One hack that avoids the reboot, is to use the vga_reset 
prog in libsvga. You run this from the console, not X; it calls the 
nvidia bios and re-inits the card.

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 13:15:07 -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 13:15:07 -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
@@ -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,7 +877,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 +900,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	5 Dec 2003 13:15:07 -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