00001
00023
00024 #include "streamlisteners.h"
00025 #include "scanstreamdata.h"
00026 #include "premieretables.h"
00027 #include "mythlogging.h"
00028 #include "atsctables.h"
00029 #include "sctetables.h"
00030 #include "ringbuffer.h"
00031 #include "dvbtables.h"
00032 #include "exitcodes.h"
00033
00034
00035 #include "mpegutils.h"
00036
00037 extern "C" {
00038 #include "libavcodec/mpegvideo.h"
00039 }
00040
00041
00042 static QHash<uint,bool> extract_pids(const QString &pidsStr, bool required)
00043 {
00044 QHash<uint,bool> use_pid;
00045 if (pidsStr.isEmpty())
00046 {
00047 if (required)
00048 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --pids option\n");
00049 }
00050 else
00051 {
00052 QStringList pidsList = pidsStr.split(",");
00053 for (uint i = 0; i < (uint) pidsList.size(); i++)
00054 {
00055 bool ok;
00056 uint tmp = pidsList[i].toUInt(&ok, 0);
00057 if (ok && (tmp < 0x2000))
00058 use_pid[tmp] = true;
00059 }
00060 if (required && use_pid.empty())
00061 {
00062 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
00063 "At least one pid must be specified\n");
00064 }
00065 }
00066 return use_pid;
00067 }
00068
00069 static int resync_stream(
00070 const char *buffer, int curr_pos, int len, int packet_size)
00071 {
00072
00073 int pos = curr_pos;
00074 int nextpos = pos + packet_size;
00075 if (nextpos >= len)
00076 return -1;
00077
00078 while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE)
00079 {
00080 pos++;
00081 nextpos++;
00082 if (nextpos == len)
00083 return -2;
00084 }
00085
00086 return pos;
00087 }
00088
00089 static int pid_counter(const MythUtilCommandLineParser &cmdline)
00090 {
00091 if (cmdline.toString("infile").isEmpty())
00092 {
00093 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --infile option\n");
00094 return GENERIC_EXIT_INVALID_CMDLINE;
00095 }
00096 QString src = cmdline.toString("infile");
00097
00098 RingBuffer *srcRB = RingBuffer::Create(src, false);
00099 if (!srcRB)
00100 {
00101 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Couldn't open input URL\n");
00102 return GENERIC_EXIT_NOT_OK;
00103 }
00104
00105 uint packet_size = cmdline.toUInt("packetsize");
00106 if (packet_size == 0)
00107 {
00108 packet_size = 188;
00109 }
00110 else if (packet_size != 188 &&
00111 packet_size != (188+16) &&
00112 packet_size != (188+20))
00113 {
00114 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
00115 QString("Invalid packet size %1, must be 188, 204, or 208\n")
00116 .arg(packet_size));
00117 return GENERIC_EXIT_INVALID_CMDLINE;
00118 }
00119
00120 const int kBufSize = 2 * 1024 * 1024;
00121 long long pid_count[0x2000];
00122 memset(pid_count, 0, sizeof(pid_count));
00123 char *buffer = new char[kBufSize];
00124 int offset = 0;
00125 long long total_count = 0;
00126
00127 while (true)
00128 {
00129 int r = srcRB->Read(&buffer[offset], kBufSize - offset);
00130 if (r <= 0)
00131 break;
00132 int pos = 0;
00133 int len = offset + r;
00134 while (pos + 187 < len)
00135 {
00136 if (buffer[pos] != SYNC_BYTE)
00137 {
00138 pos = resync_stream(buffer, pos+1, len, packet_size);
00139 if (pos < 0)
00140 {
00141 offset = 0;
00142 break;
00143 }
00144 }
00145 int pid = ((buffer[pos+1]<<8) | buffer[pos+2]) & 0x1fff;
00146 pid_count[pid]++;
00147 pos += packet_size;
00148 total_count++;
00149 }
00150
00151 if (len - pos > 0)
00152 {
00153 memcpy(buffer, buffer + pos, len - pos);
00154 offset = len - pos;
00155 }
00156 else
00157 {
00158 offset = 0;
00159 }
00160 LOG(VB_STDIO, logLevel,
00161 QString("\r \r"
00162 "Processed %1 packets")
00163 .arg(total_count));
00164 }
00165 LOG(VB_STDIO|VB_FLUSH, logLevel, "\n");
00166
00167 delete[] buffer;
00168 delete srcRB;
00169
00170 for (uint i = 0; i < 0x2000; i++)
00171 {
00172 if (pid_count[i])
00173 {
00174 LOG(VB_STDIO|VB_FLUSH, LOG_CRIT,
00175 QString("PID 0x%1 -- %2\n")
00176 .arg(i,4,16,QChar('0'))
00177 .arg(pid_count[i],11));
00178 }
00179 }
00180
00181 return GENERIC_EXIT_OK;
00182 }
00183
00184 static int pid_filter(const MythUtilCommandLineParser &cmdline)
00185 {
00186 if (cmdline.toString("infile").isEmpty())
00187 {
00188 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --infile option\n");
00189 return GENERIC_EXIT_INVALID_CMDLINE;
00190 }
00191 QString src = cmdline.toString("infile");
00192
00193 if (cmdline.toString("outfile").isEmpty())
00194 {
00195 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --outfile option\n");
00196 return GENERIC_EXIT_INVALID_CMDLINE;
00197 }
00198 QString dest = cmdline.toString("outfile");
00199
00200 uint packet_size = cmdline.toUInt("packetsize");
00201 if (packet_size == 0)
00202 {
00203 packet_size = 188;
00204 }
00205 else if (packet_size != 188 &&
00206 packet_size != (188+16) &&
00207 packet_size != (188+20))
00208 {
00209 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
00210 QString("Invalid packet size %1, must be 188, 204, or 208\n")
00211 .arg(packet_size));
00212 return GENERIC_EXIT_INVALID_CMDLINE;
00213 }
00214
00215 QHash<uint,bool> use_pid = extract_pids(cmdline.toString("pids"), true);
00216 if (use_pid.empty())
00217 return GENERIC_EXIT_INVALID_CMDLINE;
00218
00219 RingBuffer *srcRB = RingBuffer::Create(src, false);
00220 if (!srcRB)
00221 {
00222 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Couldn't open input URL\n");
00223 return GENERIC_EXIT_NOT_OK;
00224 }
00225
00226 RingBuffer *destRB = RingBuffer::Create(dest, true);
00227 if (!destRB)
00228 {
00229 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Couldn't open output URL\n");
00230 delete srcRB;
00231 return GENERIC_EXIT_NOT_OK;
00232 }
00233
00234 const int kBufSize = 2 * 1024 * 1024;
00235 char *buffer = new char[kBufSize];
00236 int offset = 0;
00237 long long total_count = 0;
00238 long long write_count = 0;
00239
00240 while (true)
00241 {
00242 int r = srcRB->Read(&buffer[offset], kBufSize - offset);
00243 if (r <= 0)
00244 break;
00245 int pos = 0;
00246 int len = offset + r;
00247 while (pos + 187 < len)
00248 {
00249 if (buffer[pos] != SYNC_BYTE)
00250 {
00251 pos = resync_stream(buffer, pos+1, len, packet_size);
00252 if (pos < 0)
00253 {
00254 offset = 0;
00255 break;
00256 }
00257 }
00258 int pid = ((buffer[pos+1]<<8) | buffer[pos+2]) & 0x1fff;
00259 if (use_pid[pid])
00260 {
00261 destRB->Write(buffer+pos, packet_size);
00262 write_count++;
00263 }
00264 pos += packet_size;
00265 total_count++;
00266 }
00267
00268 if (len - pos > 0)
00269 {
00270 memcpy(buffer, buffer + pos, len - pos);
00271 offset = len - pos;
00272 }
00273 else
00274 {
00275 offset = 0;
00276 }
00277 LOG(VB_STDIO|VB_FLUSH, logLevel,
00278 QString("\r \r"
00279 "Processed %1 packets")
00280 .arg(total_count));
00281 }
00282 LOG(VB_STDIO|VB_FLUSH, logLevel, "\n");
00283
00284 delete[] buffer;
00285 delete srcRB;
00286 delete destRB;
00287
00288 LOG(VB_STDIO|VB_FLUSH, logLevel, QString("Wrote %1 of %2 packets\n")
00289 .arg(write_count).arg(total_count));
00290
00291 return GENERIC_EXIT_OK;
00292 }
00293
00294 class PTSListener :
00295 public TSPacketListener,
00296 public TSPacketListenerAV
00297 {
00298 public:
00299 PTSListener() : m_start_code(0xFFFFFFFF)
00300 {
00301 for (int i = 0; i < 256; i++)
00302 m_pts_count[i] = 0;
00303 for (int i = 0; i < 256; i++)
00304 m_pts_first[i] = -1LL;
00305 for (int i = 0; i < 256; i++)
00306 m_pts_last[i] = -1LL;
00307
00308 }
00309 bool ProcessTSPacket(const TSPacket &tspacket);
00310 bool ProcessVideoTSPacket(const TSPacket &tspacket)
00311 { return ProcessTSPacket(tspacket); }
00312 bool ProcessAudioTSPacket(const TSPacket &tspacket)
00313 { return ProcessTSPacket(tspacket); }
00314 int64_t GetFirstPTS(void) const
00315 {
00316 QMap<uint,uint>::const_iterator it = m_pts_streams.begin();
00317 int64_t pts = -1LL;
00318 for (; it != m_pts_streams.end(); ++it)
00319 {
00320 int64_t v = m_pts_first[*it];
00321 if (v >= 0)
00322 pts = min((pts < 0) ? v : pts, v);
00323 }
00324 return pts;
00325 }
00326 int64_t GetLastPTS(void) const
00327 {
00328 QMap<uint,uint>::const_iterator it = m_pts_streams.begin();
00329 int64_t pts = -1LL;
00330 for (; it != m_pts_streams.end(); ++it)
00331 {
00332 int64_t v = m_pts_last[*it];
00333 if (v >= 0)
00334 pts = max(pts, v);
00335 }
00336 return pts;
00337 }
00338 int64_t GetElapsedPTS(void) const
00339 {
00340 int64_t elapsed = GetLastPTS() - GetFirstPTS();
00341 return (elapsed < 0) ? elapsed + 0x1000000000LL : elapsed;
00342 }
00343
00344 public:
00345 uint32_t m_start_code;
00346 QMap<uint,uint> m_pts_streams;
00347 uint32_t m_pts_count[256];
00348 int64_t m_pts_first[256];
00349 int64_t m_pts_last[256];
00350 };
00351
00352
00353 bool PTSListener::ProcessTSPacket(const TSPacket &tspacket)
00354 {
00355
00356
00357
00358 const bool payloadStart = tspacket.PayloadStart();
00359 m_start_code = (payloadStart) ? 0xffffffff : m_start_code;
00360
00361
00362
00363
00364
00365
00366 const uint8_t *bufptr = tspacket.data() + tspacket.AFCOffset();
00367 const uint8_t *bufend = tspacket.data() + TSPacket::kSize;
00368
00369 while (bufptr < bufend)
00370 {
00371 bufptr = avpriv_mpv_find_start_code(bufptr, bufend, &m_start_code);
00372 int bytes_left = bufend - bufptr;
00373 if ((m_start_code & 0xffffff00) == 0x00000100)
00374 {
00375
00376
00377 const int stream_id = m_start_code & 0x000000ff;
00378 if ((stream_id < 0xc0) || (stream_id > 0xef) ||
00379 (bytes_left < 10))
00380 {
00381 continue;
00382 }
00383 bool has_pts = bufptr[3] & 0x80;
00384 if (has_pts && (bytes_left > 5+5))
00385 {
00386 int i = 5;
00387 int64_t pts =
00388 (uint64_t(bufptr[i+0] & 0x0e) << 29) |
00389 (uint64_t(bufptr[i+1] ) << 22) |
00390 (uint64_t(bufptr[i+2] & 0xfe) << 14) |
00391 (uint64_t(bufptr[i+3] ) << 7) |
00392 (uint64_t(bufptr[i+4] & 0xfe) >> 1);
00393 m_pts_streams[stream_id] = stream_id;
00394 m_pts_last[stream_id] = pts;
00395 if (m_pts_count[stream_id] < 30)
00396 {
00397 if (!m_pts_count[stream_id])
00398 m_pts_first[stream_id] = pts;
00399 else if (pts < m_pts_first[stream_id])
00400 m_pts_first[stream_id] = pts;
00401 }
00402 m_pts_count[stream_id]++;
00403 }
00404 }
00405 }
00406
00407 return true;
00408 }
00409
00410 class PrintOutput
00411 {
00412 public:
00413 PrintOutput(RingBuffer *out, bool use_xml) :
00414 m_out(out), m_use_xml(use_xml)
00415 {
00416 }
00417
00418 void Output(const QString &msg) const
00419 {
00420 if (m_out)
00421 {
00422 QByteArray ba = msg.toUtf8();
00423 m_out->Write(ba.constData(), ba.size());
00424 }
00425 else
00426 {
00427 LOG(VB_STDIO|VB_FLUSH, logLevel, msg);
00428 }
00429 }
00430
00431 void Output(const PSIPTable *psip) const
00432 {
00433 if (!psip)
00434 return;
00435 Output(((m_use_xml) ? psip->toStringXML(0) : psip->toString()) + "\n");
00436 }
00437
00438 protected:
00439 RingBuffer *m_out;
00440 bool m_use_xml;
00441 };
00442
00443 class PrintMPEGStreamListener : public MPEGStreamListener, public PrintOutput
00444 {
00445 public:
00446 PrintMPEGStreamListener(
00447 RingBuffer *out, PTSListener &ptsl, bool autopts,
00448 MPEGStreamData *sd, const QHash<uint,bool> &use_pid, bool use_xml) :
00449 PrintOutput(out, use_xml), m_ptsl(ptsl),
00450 m_autopts(autopts), m_sd(sd), m_use_pid(use_pid)
00451 {
00452 if (m_autopts)
00453 m_sd->AddListeningPID(MPEG_PAT_PID);
00454 }
00455
00456 void HandlePAT(const ProgramAssociationTable *pat)
00457 {
00458 if (pat && (!m_autopts || m_use_pid[MPEG_PAT_PID]))
00459 Output(pat);
00460 if (pat && m_autopts)
00461 {
00462 for (uint i = 0; i < pat->ProgramCount(); i++)
00463 m_sd->AddListeningPID(pat->ProgramPID(i));
00464 }
00465 }
00466
00467 void HandleCAT(const ConditionalAccessTable *cat)
00468 {
00469 if (cat)
00470 Output(cat);
00471 }
00472
00473 void HandlePMT(uint program_num, const ProgramMapTable *pmt)
00474 {
00475 if (pmt && (!m_autopts || m_use_pid[pmt->tsheader()->PID()]))
00476 Output(pmt);
00477 if (pmt && m_autopts)
00478 {
00479 uint video_pid = 0, audio_pid = 0;
00480 for (uint i = 0; i < pmt->StreamCount(); i++)
00481 {
00482 if (pmt->IsVideo(i, "mpeg"))
00483 video_pid = pmt->StreamPID(i);
00484 else if (pmt->IsAudio(i, "mpeg"))
00485 audio_pid = pmt->StreamPID(i);
00486 }
00487 if (video_pid)
00488 m_sd->AddWritingPID(video_pid);
00489 else if (audio_pid)
00490 m_sd->AddWritingPID(audio_pid);
00491 else
00492 {
00493 LOG(VB_STDIO|VB_FLUSH, LOG_WARNING,
00494 "Couldn't find PTS stream\n");
00495 }
00496 }
00497 }
00498
00499 void HandleEncryptionStatus(uint program_number, bool)
00500 {
00501 }
00502
00503 void HandleSplice(const SpliceInformationTable *sit)
00504 {
00505 if (sit && m_use_xml)
00506 {
00507 Output(sit->toStringXML(
00508 0, m_ptsl.GetFirstPTS(), m_ptsl.GetLastPTS()) + "\n");
00509 }
00510 else if (sit)
00511 {
00512 QTime ot = QTime(0,0,0,0).addMSecs(m_ptsl.GetElapsedPTS()/90);
00513 Output(
00514 ot.toString("hh:mm:ss.zzz") + " " +
00515 sit->toString(m_ptsl.GetFirstPTS(),
00516 m_ptsl.GetLastPTS()) + "\n");
00517 }
00518 }
00519
00520 private:
00521 const PTSListener &m_ptsl;
00522 bool m_autopts;
00523 MPEGStreamData *m_sd;
00524 const QHash<uint,bool> &m_use_pid;
00525 };
00526
00527 class PrintATSCMainStreamListener :
00528 public ATSCMainStreamListener, public PrintOutput
00529 {
00530 public:
00531 PrintATSCMainStreamListener(RingBuffer *out, bool use_xml) :
00532 PrintOutput(out, use_xml) { }
00533
00534 void HandleSTT(const SystemTimeTable *stt)
00535 {
00536 Output(stt);
00537 }
00538
00539 void HandleMGT(const MasterGuideTable *mgt)
00540 {
00541 Output(mgt);
00542 }
00543
00544 void HandleVCT(uint pid, const VirtualChannelTable *vct)
00545 {
00546 Output(vct);
00547 }
00548 };
00549
00550 class PrintSCTEMainStreamListener :
00551 public SCTEMainStreamListener, public PrintOutput
00552 {
00553 public:
00554 PrintSCTEMainStreamListener(RingBuffer *out, bool use_xml) :
00555 PrintOutput(out, use_xml) { }
00556
00557 void HandleNIT(const SCTENetworkInformationTable *nit)
00558 {
00559 Output(nit);
00560 }
00561
00562 void HandleSTT(const SCTESystemTimeTable *stt)
00563 {
00564 Output(stt);
00565 }
00566
00567 void HandleNTT(const NetworkTextTable *ntt)
00568 {
00569 Output(ntt);
00570 }
00571
00572 void HandleSVCT(const ShortVirtualChannelTable *svct)
00573 {
00574 Output(svct);
00575 }
00576
00577 void HandlePIM(const ProgramInformationMessageTable *pim)
00578 {
00579 Output(pim);
00580 }
00581
00582 void HandlePNM(const ProgramNameMessageTable *pnm)
00583 {
00584 Output(pnm);
00585 }
00586
00587 void HandleADET(const AggregateDataEventTable *adet)
00588 {
00589 Output(adet);
00590 }
00591 };
00592
00593 class PrintATSCAuxStreamListener :
00594 public ATSCAuxStreamListener, public PrintOutput
00595 {
00596 public:
00597 PrintATSCAuxStreamListener(RingBuffer *out, bool use_xml) :
00598 PrintOutput(out, use_xml) { }
00599
00600 virtual void HandleTVCT(
00601 uint pid, const TerrestrialVirtualChannelTable *tvct)
00602 {
00603
00604 }
00605
00606 virtual void HandleCVCT(uint pid, const CableVirtualChannelTable *cvct)
00607 {
00608
00609 }
00610
00611 virtual void HandleRRT(const RatingRegionTable *rrt)
00612 {
00613 Output(rrt);
00614 }
00615
00616 virtual void HandleDCCT(const DirectedChannelChangeTable *dcct)
00617 {
00618 Output(dcct);
00619 }
00620
00621 virtual void HandleDCCSCT(
00622 const DirectedChannelChangeSelectionCodeTable *dccsct)
00623 {
00624 Output(dccsct);
00625 }
00626 };
00627
00628 class PrintATSCEITStreamListener :
00629 public ATSCEITStreamListener, public PrintOutput
00630 {
00631 public:
00632 PrintATSCEITStreamListener(RingBuffer *out, bool use_xml) :
00633 PrintOutput(out, use_xml) { }
00634
00635 virtual void HandleEIT(uint pid, const EventInformationTable *eit)
00636 {
00637 if (eit)
00638 Output(QString("EIT PID 0x%1\n").arg(pid,0,16) + eit->toString());
00639 }
00640
00641 virtual void HandleETT(uint pid, const ExtendedTextTable *ett)
00642 {
00643 if (ett)
00644 Output(QString("ETT PID 0x%1\n").arg(pid,0,16) + ett->toString());
00645 }
00646 };
00647
00648 class PrintDVBMainStreamListener :
00649 public DVBMainStreamListener, public PrintOutput
00650 {
00651 public:
00652 PrintDVBMainStreamListener(RingBuffer *out, bool use_xml) :
00653 PrintOutput(out, use_xml) { }
00654
00655 virtual void HandleTDT(const TimeDateTable *tdt)
00656 {
00657 Output(tdt);
00658 }
00659
00660 virtual void HandleNIT(const NetworkInformationTable *nit)
00661 {
00662 Output(nit);
00663 }
00664
00665 virtual void HandleSDT(uint tsid, const ServiceDescriptionTable *sdt)
00666 {
00667 Output(sdt);
00668 }
00669
00670 };
00671
00672 class PrintDVBOtherStreamListener :
00673 public DVBOtherStreamListener, public PrintOutput
00674 {
00675 public:
00676 PrintDVBOtherStreamListener(RingBuffer *out, bool use_xml) :
00677 PrintOutput(out, use_xml) { }
00678
00679 virtual void HandleNITo(const NetworkInformationTable *nit)
00680 {
00681 Output(nit);
00682 }
00683
00684 virtual void HandleSDTo(uint tsid, const ServiceDescriptionTable *sdt)
00685 {
00686 Output(sdt);
00687 }
00688
00689 virtual void HandleBAT(const BouquetAssociationTable *bat)
00690 {
00691 Output(bat);
00692 }
00693
00694 };
00695
00696 class PrintDVBEITStreamListener :
00697 public DVBEITStreamListener, public PrintOutput
00698 {
00699 public:
00700 PrintDVBEITStreamListener(RingBuffer *out, bool use_xml) :
00701 PrintOutput(out, use_xml) { }
00702
00703 virtual void HandleEIT(const DVBEventInformationTable *eit)
00704 {
00705 Output(eit);
00706 }
00707
00708 virtual void HandleEIT(const PremiereContentInformationTable *pcit)
00709 {
00710 Output(pcit);
00711 }
00712 };
00713
00714 static int pid_printer(const MythUtilCommandLineParser &cmdline)
00715 {
00716 if (cmdline.toString("infile").isEmpty())
00717 {
00718 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --infile option\n");
00719 return GENERIC_EXIT_INVALID_CMDLINE;
00720 }
00721 QString src = cmdline.toString("infile");
00722
00723 RingBuffer *srcRB = RingBuffer::Create(src, false);
00724 if (!srcRB)
00725 {
00726 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Couldn't open input URL\n");
00727 return GENERIC_EXIT_NOT_OK;
00728 }
00729
00730 QHash<uint,bool> use_pid = extract_pids(cmdline.toString("pids"), true);
00731 if (use_pid.empty())
00732 return GENERIC_EXIT_INVALID_CMDLINE;
00733
00734 QHash<uint,bool> use_pid_for_pts =
00735 extract_pids(cmdline.toString("ptspids"), false);
00736
00737 QString dest = cmdline.toString("outfile");
00738 RingBuffer *out = NULL;
00739 if (!dest.isEmpty())
00740 {
00741 out = RingBuffer::Create(dest, true);
00742 if (!out)
00743 {
00744 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Couldn't open output URL\n");
00745 delete srcRB;
00746 return GENERIC_EXIT_NOT_OK;
00747 }
00748 }
00749
00750 bool autopts = !cmdline.toBool("noautopts");
00751 bool use_xml = cmdline.toBool("xml");
00752
00753 ScanStreamData *sd = new ScanStreamData(true);
00754 for (QHash<uint,bool>::iterator it = use_pid.begin();
00755 it != use_pid.end(); ++it)
00756 {
00757 sd->AddListeningPID(it.key());
00758 }
00759
00760 for (QHash<uint,bool>::iterator it = use_pid_for_pts.begin();
00761 it != use_pid_for_pts.end(); ++it)
00762 {
00763 sd->AddWritingPID(it.key());
00764 }
00765
00766 PTSListener *ptsl = new PTSListener();
00767 PrintMPEGStreamListener *pmsl =
00768 new PrintMPEGStreamListener(out, *ptsl, autopts, sd, use_pid, use_xml);
00769 PrintATSCMainStreamListener *pasl =
00770 new PrintATSCMainStreamListener(out, use_xml);
00771 PrintSCTEMainStreamListener *pssl =
00772 new PrintSCTEMainStreamListener(out, use_xml);
00773 PrintATSCAuxStreamListener *paasl =
00774 new PrintATSCAuxStreamListener(out, use_xml);
00775 PrintATSCEITStreamListener *paesl =
00776 new PrintATSCEITStreamListener(out, use_xml);
00777 PrintDVBMainStreamListener *pdmsl =
00778 new PrintDVBMainStreamListener(out, use_xml);
00779 PrintDVBOtherStreamListener *pdosl =
00780 new PrintDVBOtherStreamListener(out, use_xml);
00781 PrintDVBEITStreamListener *pdesl =
00782 new PrintDVBEITStreamListener(out, use_xml);
00783
00784 sd->AddWritingListener(ptsl);
00785 sd->AddMPEGListener(pmsl);
00786 sd->AddATSCMainListener(pasl);
00787 sd->AddSCTEMainListener(pssl);
00788 sd->AddATSCAuxListener(paasl);
00789 sd->AddATSCEITListener(paesl);
00790 sd->AddDVBMainListener(pdmsl);
00791 sd->AddDVBOtherListener(pdosl);
00792 sd->AddDVBEITListener(pdesl);
00793
00794 const int kBufSize = 2 * 1024 * 1024;
00795 char *buffer = new char[kBufSize];
00796 int offset = 0;
00797 uint64_t totalBytes = 0ULL;
00798
00799 while (true)
00800 {
00801 int r = srcRB->Read(&buffer[offset], kBufSize - offset);
00802 if (r <= 0)
00803 break;
00804
00805 int len = offset + r;
00806
00807 offset = sd->ProcessData((const unsigned char*)buffer, len);
00808
00809 totalBytes += len - offset;
00810 LOG(VB_STDIO|VB_FLUSH, logLevel,
00811 QString("\r \r"
00812 "Processed %1 bytes")
00813 .arg(totalBytes));
00814 }
00815 LOG(VB_STDIO|VB_FLUSH, logLevel, "\n");
00816
00817 if (ptsl->GetFirstPTS() >= 0)
00818 {
00819 QTime ot = QTime(0,0,0,0).addMSecs(ptsl->GetElapsedPTS()/90);
00820
00821 LOG(VB_STDIO|VB_FLUSH, logLevel,
00822 QString("First PTS %1, Last PTS %2, elapsed %3 %4\n")
00823 .arg(ptsl->GetFirstPTS()).arg(ptsl->GetLastPTS())
00824 .arg(ptsl->GetElapsedPTS())
00825 .arg(ot.toString("hh:mm:ss.zzz")));
00826 }
00827
00828 delete sd;
00829 delete pmsl;
00830 delete pasl;
00831 delete pssl;
00832 delete paasl;
00833 delete paesl;
00834 delete pdmsl;
00835 delete pdosl;
00836 delete pdesl;
00837 delete ptsl;
00838
00839 delete srcRB;
00840 delete out;
00841
00842 return GENERIC_EXIT_OK;
00843 }
00844
00845 void registerMPEGUtils(UtilMap &utilMap)
00846 {
00847 utilMap["pidcounter"] = &pid_counter;
00848 utilMap["pidfilter"] = &pid_filter;
00849 utilMap["pidprinter"] = &pid_printer;
00850 }