[mythtv] hdtv reorg, crc checking

Daniel Thor Kristjansson danielk at cat.nyu.edu
Fri Jan 30 19:50:01 EST 2004


I simplified the ProcessData loop that parses TS packets by breaking the
TS packet parsing out into its own class. After this was done it was
easy to add CRC checking of PAT and PMT packets. This is still in too
much flux to be applied to cvs esp with 1.4 on the horizon, but if you are
using a hdtv card or working on this code it might be useful.

My goal is to add some kind of sanity checking, if not CRC checking, on
video and audio packets so bad packets aren't written to the stream.
(This causes crashes due to bugs in the av decoder I would also like
fixed, but one thing at a time...)

(I didn't add tspacket.h to the qmake, so either add it or touch
hdtvrecorder.cpp before a rebuild.)

-- Daniel
  << When truth is outlawed; only outlaws will tell the truth. >> - RLiegh
-------------- next part --------------
diff -u -r mythtv-clean/libs/libmythtv/hdtvrecorder.cpp mythtv-new-clean/libs/libmythtv/hdtvrecorder.cpp
--- mythtv-clean/libs/libmythtv/hdtvrecorder.cpp	2004-01-30 19:20:43.000000000 -0500
+++ mythtv-new-clean/libs/libmythtv/hdtvrecorder.cpp	2004-01-30 19:20:47.000000000 -0500
@@ -37,6 +37,10 @@
    * change expected keyframe distance to 30 frames to see if this
      lets people seek past halfway in recordings
 
+   Jan 30, 2004 by Daniel Kristjansson
+   * broke out tspacket to handle TS packets
+   * added CRC check on PAT & PMT packets
+
    References / example code: 
      ATSC standards a.54, a.69 (www.atsc.org)
      ts2pes from mpegutils from dvb (www.linuxtv.org)
@@ -62,6 +66,7 @@
 #include "RingBuffer.h"
 #include "mythcontext.h"
 #include "programinfo.h"
+#include "tspacket.h"
 
 extern "C" {
 #include "../libavcodec/avcodec.h"
@@ -72,13 +77,6 @@
 // n.b. at 19 Mbits/sec, default buffer size is approx. 1/10 sec.
 #define PACKETS (HD_BUFFER_SIZE / 188)
 
-#define SYNC_BYTE 0x47
-
-// n.b. these PID relationships are only a recommendation from ATSC,
-// but seem to be universal
-#define VIDEO_PID(bp) ((bp)+1)
-#define AUDIO_PID(bp) ((bp)+4)
-
 HDTVRecorder::HDTVRecorder()
             : RecorderBase()
 {
@@ -294,12 +292,6 @@
     
 }
 
-static unsigned int get1bit(unsigned char byte, int bit)
-{
-    bit = 7-bit;
-    return (byte & (1 << bit)) >> bit;
-}
-
 void HDTVRecorder::FindKeyframes(const unsigned char *buffer, 
                                  int packet_start_pos,
                                  int current_pos,
@@ -450,18 +442,6 @@
     return pos;
 }
 
-void HDTVRecorder::RewritePID(unsigned char *buffer, int pid)
-{
-    // We need to rewrite the outgoing PIDs to match the first one
-    // the decoder saw ... it does not seem to track PID changes.
-    char b1, b2;
-    // PID is 13 bits starting in byte 1, bit 4
-    b1 = ((pid >> 8) & 0x1F) | (buffer[1] & 0xE0);
-    b2 = (pid & 0xFF);
-    buffer[1] = b1;
-    buffer[2] = b2;
-}
-
 bool HDTVRecorder::RewritePAT(unsigned char *buffer, int pid, int pkt_len)
 {
     int pos = 0;
@@ -488,7 +468,7 @@
 
     pos = 8;  // section header is 8 bytes, skip it
 
-    buffer[pos] = 0x00;
+    buffer[pos+0] = 0x00;
     buffer[pos+1] = 0x01;
     buffer[pos+2] = 0xe0 | ((pid & 0x1f00) >> 8);
     buffer[pos+3] = pid & 0xff;
@@ -499,15 +479,10 @@
     buffer[1] = (buffer[1] & 0xf0) | ((new_len & 0x0f00) >> 8);
     buffer[2] = new_len & 0xff;
 
-    // fix the checksum
-    unsigned int crc = mpegts_crc32(buffer, pos);
-    buffer[pos++] = (crc & 0xff000000) >> 24;
-    buffer[pos++] = (crc & 0x00ff0000) >> 16;
-    buffer[pos++] = (crc & 0x0000ff00) >> 8;
-    buffer[pos++] = (crc & 0x000000ff);
+    TSPacket::fixCRC(buffer, pos);
 
     // pad the rest of the packet with 0xff
-    memset(buffer + pos, 0xff, pkt_len - pos);
+    memset(buffer + pos + 4, 0xff, pkt_len - (pos + 4));
 
     return true;
 }
@@ -579,229 +554,32 @@
     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;
-    buffer[sec_len - 3] = (crc & 0x00ff0000) >> 16;
-    buffer[sec_len - 2] = (crc & 0x0000ff00) >> 8;
-    buffer[sec_len - 1] = (crc & 0x000000ff);
+    //int old_len = (buffer[1] & 0x0f) << 8 | buffer[2];
+    //cerr<<"f"<<pos<<" "<<old_len<<":"<<new_len<<endl;
+    TSPacket::fixCRC(buffer, sec_len - 4);
 
     return true;
 }
 
-    
-int HDTVRecorder::ProcessData(unsigned char *buffer, int len)
-{
-    int pos = 0;
-    int packet_end_pos;
-    int packet_start_pos;
-    int pid;
-    bool payload_unit_start_indicator;
-    char adaptation_field_control;
-
-    while (pos + 187 < len) // while we have a whole packet left
-    {
-        if (buffer[pos] != SYNC_BYTE)
-        {
-            int newpos = ResyncStream(buffer, pos, len);
-            if (newpos == -1)
-                return len - pos;
-            if (newpos == -2)
-                return 188;
-            
-            pos = newpos;
-        }
-
-        ts_packets++;
-        packet_start_pos = pos;
-        packet_end_pos = pos + 188;
-        pos++;
-        
-        // Decode the link header (next 3 bytes):
-        //   1 bit transport_packet_error (if set discard immediately: 
-        //      modem error)
-        //   1 bit payload_unit_start_indicator (if set this 
-        //      packet starts a PES packet)
-        //   1 bit transport_priority (ignore)
-        //   13 bit PID (packet ID, which transport stream)
-        //   2 bit transport_scrambling_control (00,01 OK; 10,11 scrambled)
-        //   2 bit adaptation_field_control 
-        //     (01-no adptation field,payload only
-        //      10-adaptation field only,no payload
-        //      11-adaptation field followed by payload
-        //      00-reserved)
-        //   4 bit continuity counter (should cycle 0->15 in sequence 
-        //     for each PID; if skip, we lost a packet; if dup, we can
-        //     ignore packet)
-
-        if (get1bit(buffer[pos], 0))
-        {
-            // transport_packet_error -- skip packet but don't skip
-            // ahead, let it resync in case modem dropped a byte
-            continue;
-        }
-        payload_unit_start_indicator = (get1bit(buffer[pos], 1));
-        pid = ((buffer[pos] << 8) + buffer[pos+1]) & 0x1fff;
-        //cerr << "found PID " << pid << endl;
-        pos += 2;
-        if (get1bit(buffer[pos], 1)) 
-        {
-            // packet is from a scrambled stream
-            pos = packet_end_pos;
-            continue;
-        }
-        adaptation_field_control = (buffer[pos] & 0x30) >> 4;
-        pos++;
-        
-        if (adaptation_field_control == 2 || adaptation_field_control == 3)
-        {
-            // If we later care about any adaptation layer bits,
-            // we should parse them here:
-            /*
-              8 bit adaptation header length (after which is payload data)
-              1 bit discontinuity_indicator (time base may change)
-              1 bit random_access_indicator (?)
-              1 bit elementary_stream_priority_indicator (ignore)
-              Each of the following extends the adaptation header.  In order:
-              1 bit PCR flag (we have PCR data) (adds 6 bytes after adaptation 
-                  header)
-              1 bit OPCR flag (we have OPCR data) (adds 6 bytes)
-                   ((Original) Program Clock Reference; used to time output)
-              1 bit splicing_point_flag (we have splice point data) 
-                   (adds 1 byte)
-                   (splice data is packets until a good splice point for 
-                   e.g. commercial insertion -- if these are still set,
-                   might be a good way to recognize potential commercials 
-                   for flagging)
-              1 bit transport_private_data_flag 
-                   (adds 1 byte additional bytecount)
-              1 bit adaptation_field_extension_flag
-              8 bits extension length
-              1 bit ltw flag (adds 16 bits after extension flags)
-              1 bit piecewise_rate_flag (adds 24 bits)
-              1 bit seamless_splice_flag (adds 40 bits)
-              5 bits unused flags
-            */
-            unsigned char adaptation_length;
-            adaptation_length = buffer[pos++];
-            pos += adaptation_length;
-        }
-
-        //
-        // Pass or reject frames based on PID, and parse info from them
-        //
-
-        if (pid == pat_pid) 
-        {
-
-            // PID 0: Program Association Table -- lists all other
-            // PIDs that make up the program(s) in the whole stream.
-            // Based on info in this table, and on which subprogram
-            // the user desires, we should determine which PIDs'
-            // payloads to write to the ring buffer.
-
-            // Example PAT scan code is in the pcHDTV's dtvscan.c,
-            // demux_ts_parse_pat
-
-            // NOTE: Broadcasters are encouraged to keep the
-            // subprogram:PID mapping constant.  If we store this data
-            // in the channel database, we can branch-predict which
-            // PIDs we are looking for, and can thus "tune" the
-            // subprogram more quickly.
-
-            // 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.
-            //
-            // 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;
-            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];
-            }
-            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)
-        {
-            // Here we should decode the PSIP and fill guide data
-            // decoder does not need psip
+int HDTVRecorder::ProcessData(unsigned char *buffer, int len) {
+  int pos = 0;
 
-            // Some sample code is in pcHDTV's dtvscan.c,
-            // accum_sect/dequeue_buf/atsc_tables.  We should stuff
-            // this data back into the channel's guide data, though if
-            // it's unreliable we will need to be able to prefer the
-            // downloaded XMLTV data.
-
-        }
-        else if (pid == video_pid)
-        {
-            FindKeyframes(buffer, packet_start_pos, pos, 
-                    adaptation_field_control, payload_unit_start_indicator);
-            // decoder needs video, of course (just this PID)
-            if (gopset || firstgoppos) 
-            {
-                 // delay until first GOP to avoid decoder crash on res change
-                RewritePID(&(buffer[packet_start_pos]), 
-                           VIDEO_PID(output_base_pid));
-                ringBuffer->Write(&buffer[packet_start_pos], 188);
-            }
-        }
-        else if (pid == audio_pid)
-        {
-            // decoder needs audio, of course (just this PID)
-            if (gopset || firstgoppos) 
-            {
-                RewritePID(&(buffer[packet_start_pos]), 
-                           AUDIO_PID(output_base_pid));
-                ringBuffer->Write(&buffer[packet_start_pos], 188);
-            }
-        }
-        else if (pid == pmt_pid)
-        {
-            // decoder needs base PID
-            int sec_start = pos + buffer[pos] + 1;
-            RewritePID(&(buffer[packet_start_pos]), output_base_pid);
-
-            // if it's a PMT table, rewrite the PIDs contained in it too
-            if (buffer[sec_start] == 0x02) {
-                if (RewritePMT(&(buffer[sec_start]), output_base_pid,
-                               packet_end_pos - sec_start))
-                {
-                    ringBuffer->Write(&buffer[packet_start_pos], 188);
-                }
-            }
-            else {
-                // some other kind of packet?  possible?  do we care?
-                ringBuffer->Write(&buffer[packet_start_pos], 188);
-            }
-        }
-        // Advance to next TS packet
-        pos = packet_end_pos;
-    }
+  while (pos + 187 < len) { // while we have a whole packet left..
+    if (buffer[pos] != SYNC_BYTE) {
+      int newpos = ResyncStream(buffer, pos, len);
+      if (newpos == -1)	return len - pos;
+      if (newpos == -2)	return 188;
+      pos = newpos;
+    }
+    ts_packets++;
+
+    if (TSPacket(*this, &buffer[pos]).process()) 
+      pos+=188; // Advance to next TS packet
+    else // Let it resync in case of dropped bytes
+      buffer[pos]=SYNC_BYTE+1;
+  }
 
-    return len - pos;
+  return len - pos;
 }
 
 void HDTVRecorder::StopRecording(void)
diff -u -r mythtv-clean/libs/libmythtv/hdtvrecorder.h mythtv-new-clean/libs/libmythtv/hdtvrecorder.h
--- mythtv-clean/libs/libmythtv/hdtvrecorder.h	2004-01-30 19:20:43.000000000 -0500
+++ mythtv-new-clean/libs/libmythtv/hdtvrecorder.h	2004-01-30 19:20:47.000000000 -0500
@@ -5,9 +5,11 @@
 
 struct AVFormatContext;
 struct AVPacket;
+class TSPacket;
 
 class HDTVRecorder : public RecorderBase
 {
+  friend class TSPacket;
   public:
     HDTVRecorder();
    ~HDTVRecorder();
@@ -55,9 +57,10 @@
                        bool payload_unit_start_indicator);
 
     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 new_pid, int pkt_len);
+
     bool recording;
     bool encoding;
 
-------------- next part --------------
#include <iostream>
#include <pthread.h>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <ctime>
#include "videodev_myth.h"

using namespace std;

#include "hdtvrecorder.h"
#include "RingBuffer.h"
#include "mythcontext.h"
#include "programinfo.h"

extern "C" {
#include "../libavcodec/avcodec.h"
#include "../libavformat/avformat.h"
#include "../libavformat/mpegts.h"
}

// n.b. these PID relationships are only a recommendation from ATSC,
// but seem to be universal
#define VIDEO_PID(bp) ((bp)+1)
#define AUDIO_PID(bp) ((bp)+4)
#define SYNC_BYTE 0x47

inline static unsigned int get1bit(unsigned char byte, int bit);

class TSPacket {
      // Decode the link header (bytes 1-4):
      //   1 bit transport_packet_error (if set discard immediately: 
      //      modem error)
      //   1 bit payload_unit_start_indicator (if set this 
      //      packet starts a PES packet)
      //   1 bit transport_priority (ignore)
      //   13 bit PID (packet ID, which transport stream)
      //   2 bit transport_scrambling_control (00,01 OK; 10,11 scrambled)
      //   2 bit adaptation_field_control 
      //     (01-no adptation field,payload only
      //      10-adaptation field only,no payload
      //      11-adaptation field followed by payload
      //      00-reserved)
      //   4 bit continuity counter (should cycle 0->15 in sequence 
      //     for each PID; if skip, we lost a packet; if dup, we can
      //     ignore packet)
public:
  TSPacket(HDTVRecorder& rec, unsigned char *ptr) : recorder(rec), packet(ptr) { ; }
  bool transportError() const { return get1bit(packet[1], 0); }
  bool scrampled() const { return get1bit(packet[3], 1); }
  bool inSync() { return SYNC_BYTE == packet[0]; }
  inline int pid() const { return ((packet[1] << 8) + packet[2]) & 0x1fff; }
  inline void setPID(int pid);
  static inline bool checkCRC(unsigned char *pes_packet); // only for PES packets 
  static inline void fixCRC(unsigned char *pes_packet, int pos); // only for PES packets 

  bool process();
  int handleAdaptationFieldControl();
  void handlePSIP();
  bool handlePAT();
  void handleVideo();
  void handleAudio();
  bool handlePMT();

private:
  HDTVRecorder& recorder;
  unsigned char *packet;
};

bool TSPacket::process() {
  bool ok=!transportError();
  if (ok && !scrampled()) {
    int lpid = pid();
    // Pass or reject frames based on PID, and parse info from them
    if (lpid==recorder.pat_pid)
      ok=handlePAT();
    else if (lpid==recorder.psip_pid)
      handlePSIP();
    else if (lpid==recorder.video_pid)
      handleVideo();
    else if (lpid==recorder.audio_pid)
      handleAudio();
    else if (lpid==recorder.pmt_pid)
      ok=handlePMT();
  }
  return ok;
}

int TSPacket::handleAdaptationFieldControl() {
  int adaptation_field_control = (packet[3] & 0x30) >> 4;
  if (adaptation_field_control == 2 || adaptation_field_control == 3) {
    // If we later care about any adaptation layer bits,
    // we should parse them here:
    /*
      8 bit adaptation header length (after which is payload data)
      1 bit discontinuity_indicator (time base may change)
      1 bit random_access_indicator (?)
      1 bit elementary_stream_priority_indicator (ignore)
      Each of the following extends the adaptation header.  In order:
      1 bit PCR flag (we have PCR data) (adds 6 bytes after adaptation 
      header)
      1 bit OPCR flag (we have OPCR data) (adds 6 bytes)
      ((Original) Program Clock Reference; used to time output)
      1 bit splicing_point_flag (we have splice point data) 
      (adds 1 byte)
      (splice data is packets until a good splice point for 
      e.g. commercial insertion -- if these are still set,
      might be a good way to recognize potential commercials 
      for flagging)
      1 bit transport_private_data_flag 
      (adds 1 byte additional bytecount)
      1 bit adaptation_field_extension_flag
      8 bits extension length
      1 bit ltw flag (adds 16 bits after extension flags)
      1 bit piecewise_rate_flag (adds 24 bits)
      1 bit seamless_splice_flag (adds 40 bits)
      5 bits unused flags
    */
    unsigned char adaptation_length;
    adaptation_length = packet[4];
    return adaptation_length+1+4;
  }
  return 4;
}
    
void TSPacket::handlePSIP() {
  handleAdaptationFieldControl();
  // Here we should decode the PSIP and fill guide data
  // decoder does not need psip
  
  // Some sample code is in pcHDTV's dtvscan.c,
  // accum_sect/dequeue_buf/atsc_tables.  We should stuff
  // this data back into the channel's guide data, though if
  // it's unreliable we will need to be able to prefer the
  // downloaded XMLTV data.
}

bool TSPacket::handlePAT() {
  // PID 0: Program Association Table -- lists all other
  // PIDs that make up the program(s) in the whole stream.
  // Based on info in this table, and on which subprogram
  // the user desires, we should determine which PIDs'
  // payloads to write to the ring buffer.

  // Example PAT scan code is in the pcHDTV's dtvscan.c,
  // demux_ts_parse_pat

  // NOTE: Broadcasters are encouraged to keep the
  // subprogram:PID mapping constant.  If we store this data
  // in the channel database, we can branch-predict which
  // PIDs we are looking for, and can thus "tune" the
  // subprogram more quickly.

  // 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.
  //
  // 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 pos=handleAdaptationFieldControl();
  int sec_start = pos + packet[pos] + 1;
  if (!checkCRC(&packet[sec_start])) {
    cerr<<"PAT packet failed CRC check"<<endl;
    return false; // need to resync...
  }

  int sec_len = (packet[sec_start + 1] & 0x0f) << 8 | packet[sec_start + 2];
  int i;
  recorder.pmt_pid = -1;

  for (i = sec_start + 8; i < sec_start + 3 + sec_len - 4; i += 4) {
    int prog_num = (packet[i] << 8) | packet[i + 1];
    int prog_pid = (packet[i + 2] & 0x0e) << 8 | packet[i + 3];
    if (prog_num == recorder.desired_program) {
      recorder.pmt_pid = prog_pid;
      break;
    }
  }
  if (recorder.pmt_pid == -1) {
    recorder.pmt_pid = (packet[sec_start + 8 + 2] & 0x0e) << 8 |
      packet[sec_start + 8 + 3];
  }
  recorder.output_base_pid = 16;

  // write to ringbuffer if pids gets rewritten successfully.
  if (recorder.RewritePAT(&packet[sec_start], recorder.output_base_pid,
			  188 - sec_start))
    recorder.ringBuffer->Write(packet, 188);
  return true; // everything ok
}

void TSPacket::handleVideo() {
  int pos=handleAdaptationFieldControl();
  bool payload_unit_start_indicator = (get1bit(packet[1], 1));
  int adaptation_field_control = (packet[3] & 0x30) >> 4;
  recorder.FindKeyframes(packet, 0, pos, 
			 adaptation_field_control, payload_unit_start_indicator);
  // decoder needs video, of course (just this PID)
  // delay until first GOP to avoid decoder crash on res change
  if (recorder.gopset || recorder.firstgoppos) {
    setPID(VIDEO_PID(recorder.output_base_pid));
    recorder.ringBuffer->Write(packet, 188);
  }
}

void TSPacket::handleAudio() {
  handleAdaptationFieldControl();
  //int sec_len = ((buffer[packet_start_pos+3] & 0x0f) << 8) + 
  //   buffer[packet_start_pos+4];
  // decoder needs audio, of course (just this PID)
  if (recorder.gopset || recorder.firstgoppos) {
    setPID(AUDIO_PID(recorder.output_base_pid));
    recorder.ringBuffer->Write(packet, 188);
  }
}

bool TSPacket::handlePMT() {
  int pos=handleAdaptationFieldControl();
  int sec_start = pos + packet[pos] + 1;
  if (!checkCRC(&packet[sec_start])) {
    cerr<<"PMT packet failed CRC check";
    return false; // need to resync...
  }

  // decoder needs base PID
  setPID(recorder.output_base_pid);
  
  // if it's a PMT table, rewrite the PIDs contained in it too
  if (packet[sec_start] == 0x02) {
    if (recorder.RewritePMT(&(packet[sec_start]), recorder.output_base_pid,
			    188 - sec_start))
      recorder.ringBuffer->Write(packet, 188);
  }
  else // some other kind of packet?  possible?  do we care?
    recorder.ringBuffer->Write(packet, 188);
  return true;
}

inline static unsigned int get1bit(unsigned char byte, int bit) {
    bit = 7-bit;
    return (byte & (1 << bit)) >> bit;
}

// fix the checksum
inline void TSPacket::fixCRC(unsigned char* pes_packet, int pos) {
  unsigned int crc = mpegts_crc32(pes_packet, pos);
  pes_packet[pos+0] = (crc & 0xff000000) >> 24;
  pes_packet[pos+1] = (crc & 0x00ff0000) >> 16;
  pes_packet[pos+2] = (crc & 0x0000ff00) >> 8;
  pes_packet[pos+3] = (crc & 0x000000ff);
}

inline bool TSPacket::checkCRC(unsigned char* pes_packet) {
  // PES packet contains
  // packet start code      24 bits
  // stream id               8 bits   packet[0]
  // PES packet length      16 bits   [1] [2]
  // PES header options      8 bits   [3]
  //   ?                             2 bits 
  //   scrambling                    2 bits
  //   priority                      1 bits
  //   data alignment                1 bits
  //   restrictions                  1 bits
  //   master                        1 bits
  //   content flags ?       8 bits   [4]
  // PES header length       8 bits   [5]
  // Option field
  //   PTS DTS              33 | 66 bits (time stamps)
  //   ESCR                 33+9 bits (+9 if PTS DTS is 33?)
  //   ES rate              22 bits
  //   DSM mode              8 bits
  //   restrictions          7 bits
  //   PES CRC              16 bits
  //   flags                 8 bits
  // More Option field     ??? bits
  // Stuffing Byte
  // PES packet data bytes
  int sec_len = (pes_packet[1] & 0x0f) << 8 | pes_packet[2];
  int pos=sec_len-1;
  unsigned int crc = mpegts_crc32(pes_packet, pos);
  return true; // todo fix..
  return ((pes_packet[pos+0]==(crc & 0xff000000) >> 24) &&
	  (pes_packet[pos+1]==(crc & 0x00ff0000) >> 16) &&
	  (pes_packet[pos+2]==(crc & 0x0000ff00) >> 8) &&
	  (pes_packet[pos+3]==(crc & 0x000000ff)));
}

inline void TSPacket::setPID(int pid) {
  // We need to rewrite the outgoing PIDs to match the first one
  // the decoder saw ... it does not seem to track PID changes.
  char b1, b2;
  // PID is 13 bits starting in byte 1, bit 4
  b1 = ((pid >> 8) & 0x1F) | (packet[1] & 0xE0);
  b2 = (pid & 0xFF);
  packet[1] = b1;
  packet[2] = b2;
}



More information about the mythtv-dev mailing list