Ticket #712: hdtvrec-drb.patch
File hdtvrec-drb.patch, 32.5 KB (added by , 18 years ago) |
---|
-
libs/libmythtv/hdtvrecorder.h
3 3 * HDTVRecorder 4 4 * Copyright (c) 2003-2004 by Brandon Beattie, Doug Larrick, 5 5 * Jason Hoos, and Daniel Thor Kristjansson 6 * Device ringbuffer added by John Poet7 6 * Distributed as part of MythTV under GPL v2 and later. 8 7 */ 9 8 … … 12 11 13 12 #include "dtvrecorder.h" 14 13 #include "tsstats.h" 14 #include "DeviceReadBuffer.h" 15 15 16 16 struct AVFormatContext; 17 17 struct AVPacket; … … 28 28 * 29 29 * \sa DTVRecorder, DVBRecorder 30 30 */ 31 class HDTVRecorder : public DTVRecorder 31 class HDTVRecorder : public DTVRecorder, private ReaderPausedCB 32 32 { 33 33 Q_OBJECT 34 34 friend class ATSCStreamData; 35 35 friend class TSPacketProcessor; 36 36 public: 37 enum {report_loops = 20000};38 39 37 HDTVRecorder(TVRec *rec); 40 38 ~HDTVRecorder(); 41 39 … … 47 45 void StartRecording(void); 48 46 void StopRecording(void); 49 47 50 void Pause(bool clear = false);51 bool IsPaused(void) const;52 53 48 void Reset(void); 54 49 55 50 bool Open(void); … … 61 56 void deleteLater(void); 62 57 63 58 private: 59 bool IsOpen(void) const { return _stream_fd >= 0; } 60 bool Close(void); 61 64 62 void TeardownAll(void); 65 int ProcessData(unsigned char *buffer,int len);63 uint ProcessDataTS(unsigned char *buffer, uint len); 66 64 bool ProcessTSPacket(const TSPacket& tspacket); 67 65 void HandleVideo(const TSPacket* tspacket); 68 66 void HandleAudio(const TSPacket* tspacket); 69 67 70 68 int ResyncStream(unsigned char *buffer, int curr_pos, int len); 71 69 72 static void *boot_ringbuffer(void *); 73 void fill_ringbuffer(void); 74 int ringbuf_read(unsigned char *buffer, size_t count); 70 void ReaderPaused(int fd); 71 bool PauseAndWait(int timeout = 100); 75 72 76 private slots: 73 bool readchan(int chanfd, unsigned char* buffer, int dlen); 74 bool syncchan(int chanfd, int dlen, int keepsync); 75 76 private slots: 77 77 void WritePAT(ProgramAssociationTable*); 78 78 void WritePMT(ProgramMapTable*); 79 79 void ProcessMGT(const MasterGuideTable*); 80 80 void ProcessVCT(uint, const VirtualChannelTable*); 81 private:82 ATSCStreamData* _atsc_stream_data;83 81 82 private: 83 ATSCStreamData *_atsc_stream_data; 84 DeviceReadBuffer *_drb; 85 84 86 // statistics 85 TSStats _ts_stats; 86 long long _resync_count; 87 size_t loop; 87 TSStats _ts_stats; 88 long long _resync_count; 88 89 89 // Data for managing the device ringbuffer 90 struct { 91 pthread_t thread; 92 mutable pthread_mutex_t lock; 93 mutable pthread_mutex_t lock_stats; 94 95 bool run; 96 bool eof; 97 bool error; 98 bool request_pause; 99 bool paused; 100 size_t size; 101 size_t used; 102 size_t max_used; 103 size_t avg_used; 104 size_t avg_cnt; 105 size_t dev_read_size; 106 size_t min_read; 107 unsigned char * buffer; 108 unsigned char * readPtr; 109 unsigned char * writePtr; 110 unsigned char * endPtr; 111 } ringbuf; 90 /// unsynced packets to look at before giving up initially 91 static const uint INIT_SYNC_WINDOW_SIZE; 92 /// synced packets to require before starting recording 93 static const uint INIT_MIN_NUM_SYNC_PACKETS; 112 94 }; 113 95 114 96 #endif -
libs/libmythtv/hdtvrecorder.cpp
84 84 #include "atsctables.h" 85 85 #include "atscstreamdata.h" 86 86 #include "tv_rec.h" 87 #include "DeviceReadBuffer.h" 87 88 88 89 // AVLib/FFMPEG includes 89 90 #include "../libavcodec/avcodec.h" 90 91 #include "../libavformat/avformat.h" 91 92 #include "../libavformat/mpegts.h" 92 93 93 #define REPORT_RING_STATS 1 94 #define LOC QString("HDTVRec(%1):").arg(videodevice) 95 #define LOC_ERR QString("HDTVRec(%1) Error:").arg(videodevice) 94 96 95 97 #define DEFAULT_SUBCHANNEL 1 96 98 … … 109 111 }; 110 112 #endif 111 113 114 const uint HDTVRecorder::INIT_SYNC_WINDOW_SIZE = 50; 115 const uint HDTVRecorder::INIT_MIN_NUM_SYNC_PACKETS = 10; 116 112 117 HDTVRecorder::HDTVRecorder(TVRec *rec) 113 118 : DTVRecorder(rec, "HDTVRecorder"), _atsc_stream_data(0), _resync_count(0) 114 119 { … … 116 121 connect(_atsc_stream_data, SIGNAL(UpdatePATSingleProgram( 117 122 ProgramAssociationTable*)), 118 123 this, SLOT(WritePAT(ProgramAssociationTable*))); 119 connect(_atsc_stream_data, SIGNAL(UpdatePMTSingleProgram(ProgramMapTable*)), 120 this, SLOT(WritePMT(ProgramMapTable*))); 124 connect(_atsc_stream_data, 125 SIGNAL(UpdatePMTSingleProgram(ProgramMapTable*)), 126 this, 127 SLOT(WritePMT(ProgramMapTable*))); 121 128 connect(_atsc_stream_data, SIGNAL(UpdateMGT(const MasterGuideTable*)), 122 129 this, SLOT(ProcessMGT(const MasterGuideTable*))); 123 130 connect(_atsc_stream_data, … … 125 132 this, SLOT(ProcessVCT(uint, const VirtualChannelTable*))); 126 133 127 134 _buffer_size = TSPacket::SIZE * 1500; 128 if ((_buffer = new unsigned char[_buffer_size])) { 129 // make valgrind happy, initialize buffer memory 135 _buffer = new unsigned char[_buffer_size]; 136 137 // make valgrind happy, initialize buffer memory 138 if (_buffer) 130 139 memset(_buffer, 0xFF, _buffer_size); 131 }132 140 133 VERBOSE(VB_RECORD, QString("HD buffer size %1 KB").arg(_buffer_size/1024)); 141 VERBOSE(VB_RECORD, LOC + 142 QString("buffer size %1 KB").arg(_buffer_size/1024)); 134 143 135 ringbuf.run = false; 136 ringbuf.buffer = 0; 137 pthread_mutex_init(&ringbuf.lock, NULL); 138 pthread_mutex_init(&ringbuf.lock_stats, NULL); 139 loop = random() % (report_loops / 2); 144 _drb = new DeviceReadBuffer(this); 140 145 } 141 146 142 147 void HDTVRecorder::TeardownAll(void) 143 148 { 144 // Make SURE that the ringbuffer thread is cleaned up149 // Make SURE that the device read thread is cleaned up -- John Poet 145 150 StopRecording(); 146 151 147 if (_stream_fd >= 0) 148 { 149 close(_stream_fd); 150 _stream_fd = -1; 151 } 152 Close(); 153 152 154 if (_atsc_stream_data) 153 155 { 154 156 delete _atsc_stream_data; … … 164 166 HDTVRecorder::~HDTVRecorder() 165 167 { 166 168 TeardownAll(); 167 pthread_mutex_destroy(&ringbuf.lock); 168 pthread_mutex_destroy(&ringbuf.lock_stats); 169 delete _drb; 169 170 } 170 171 171 172 void HDTVRecorder::deleteLater(void) … … 189 190 SetOption("vbiformat", gContext->GetSetting("VbiFormat")); 190 191 } 191 192 192 bool HDTVRecorder::Open( )193 bool HDTVRecorder::Open(void) 193 194 { 194 195 if (!_atsc_stream_data || !_buffer) 195 196 return false; 196 197 197 198 #if FAKE_VIDEO 198 199 // open file instead of device 199 if (_stream_fd >=0 && close(_stream_fd))200 {201 VERBOSE(VB_IMPORTANT,202 QString("HDTVRecorder::Open(): Error, failed to close "203 "existing fd (%1)").arg(strerror(errno)));204 return false;205 }206 200 201 Close(); // close old video file 207 202 _stream_fd = open(FAKE_VIDEO_FILES[fake_video_index], O_RDWR); 208 VERBOSE(VB_IMPORTANT, QString("Opened fake video source %1").arg(FAKE_VIDEO_FILES[fake_video_index])); 209 fake_video_index = (fake_video_index+1)%FAKE_VIDEO_NUM; 203 204 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Opened fake video source '%1'") 205 .arg(FAKE_VIDEO_FILES[fake_video_index]) + ENO); 206 207 fake_video_index = (fake_video_index + 1) % FAKE_VIDEO_NUM; 208 210 209 #else 211 if ( _stream_fd <= 0)210 if (!IsOpen()) 212 211 _stream_fd = open(videodevice.ascii(), O_RDWR); 213 212 #endif 214 if (_stream_fd <= 0) 213 214 if (!IsOpen()) 215 215 { 216 VERBOSE(VB_IMPORTANT, QString("Can't open video device: %1 chanfd = %2")217 .arg(videodevice).arg(_stream_fd));218 perror("open video:");216 VERBOSE(VB_IMPORTANT, LOC_ERR + 217 QString("Couldn't open video device: '%1'") 218 .arg(videodevice) + ENO); 219 219 } 220 return (_stream_fd>0); 220 221 return IsOpen(); 221 222 } 222 223 224 bool HDTVRecorder::Close(void) 225 { 226 if (IsOpen() && (0 != close(_stream_fd))) 227 { 228 VERBOSE(VB_IMPORTANT, LOC_ERR + 229 "Failed to close file descriptor." + ENO); 230 return false; 231 } 232 _stream_fd = -1; 233 return true; 234 } 235 223 236 void HDTVRecorder::SetStreamData(ATSCStreamData *stream_data) 224 237 { 225 238 if (stream_data == _atsc_stream_data) … … 231 244 delete old_data; 232 245 } 233 246 234 bool readchan(int chanfd, unsigned char* buffer, int dlen) { 247 bool HDTVRecorder::readchan(int chanfd, unsigned char* buffer, int dlen) 248 { 235 249 int len = read(chanfd, buffer, dlen); // read next byte 236 250 if (dlen != len) 237 251 { 238 252 if (len < 0) 239 253 { 240 VERBOSE(VB_IMPORTANT, QString("HD1 error reading from device"));241 perror("read");254 VERBOSE(VB_IMPORTANT, LOC_ERR + 255 "Reading from device failed" + ENO); 242 256 } 243 257 else if (len == 0) 244 VERBOSE(VB_IMPORTANT, QString("HD2 end of file found in packet"));258 VERBOSE(VB_IMPORTANT, LOC_ERR + "EOF found in TS packet"); 245 259 else 246 VERBOSE(VB_IMPORTANT, QString("HD3 partial read. This shouldn't happen!")); 260 VERBOSE(VB_IMPORTANT, LOC_ERR + 261 "Partial read during initial TS sync phase"); 247 262 } 248 263 return (dlen == len); 249 264 } 250 265 251 bool syncchan(int chanfd, int dlen, int keepsync) { 266 bool HDTVRecorder::syncchan(int chanfd, int dlen, int keepsync) 267 { 252 268 unsigned char b[188]; 253 269 int i, j; 254 for (i=0; i<dlen; i++) { 270 for (i=0; i<dlen; i++) 271 { 255 272 if (!readchan(chanfd, b, 1)) 256 273 break; 257 274 if (SYNC_BYTE == b[0]) 258 275 { 259 if (readchan(chanfd, &b[1], TSPacket::SIZE-1)) { 276 if (readchan(chanfd, &b[1], TSPacket::SIZE-1)) 277 { 260 278 i += (TSPacket::SIZE - 1); 261 279 for (j=0; j<keepsync; j++) 262 280 { … … 268 286 } 269 287 if (j==keepsync) 270 288 { 271 VERBOSE(VB_RECORD, 272 QString("HD4 obtained device stream sync after reading %1 bytes"). 273 arg(dlen)); 289 VERBOSE(VB_RECORD, LOC + "Obtained TS sync, "+ 290 QString("after reading %1 bytes").arg(dlen)); 274 291 return true; 275 292 } 276 293 continue; … … 278 295 break; 279 296 } 280 297 } 281 VERBOSE(VB_IMPORTANT, QString("HD5 Error: could not obtain sync"));298 VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not obtain TS sync"); 282 299 return false; 283 300 } 284 301 285 void * HDTVRecorder::boot_ringbuffer(void * arg) 286 { 287 HDTVRecorder *dtv = (HDTVRecorder *)arg; 288 dtv->fill_ringbuffer(); 289 return NULL; 290 } 302 #define SR_CHK(MSG) \ 303 if (!ok) { VERBOSE(VB_IMPORTANT, MSG); _error = true; return; } 291 304 292 void HDTVRecorder:: fill_ringbuffer(void)305 void HDTVRecorder::StartRecording(void) 293 306 { 294 int errcnt = 0; 295 int len; 296 size_t unused, used; 297 size_t contiguous; 298 size_t read_size; 299 bool run, request_pause, paused; 307 bool ok = true; 308 uint len = 0; 309 uint remainder = 0; 300 310 301 pthread_mutex_lock(&ringbuf.lock); 302 ringbuf.run = true; 303 pthread_mutex_unlock(&ringbuf.lock); 311 VERBOSE(VB_RECORD, LOC + "StartRecording()"); 304 312 305 for (;;) 306 { 307 pthread_mutex_lock(&ringbuf.lock); 308 run = ringbuf.run; 309 unused = ringbuf.size - ringbuf.used; 310 request_pause = ringbuf.request_pause; 311 paused = ringbuf.paused; 312 pthread_mutex_unlock(&ringbuf.lock); 313 ok = Open(); 314 SR_CHK("Failed to open device."); 313 315 314 if (!run)315 break;316 ok = _drb->Setup(videodevice, _stream_fd); 317 SR_CHK("Failed to allocate device read buffer."); 316 318 317 if (request_pause) 318 { 319 pthread_mutex_lock(&ringbuf.lock); 320 ringbuf.paused = true; 321 pthread_mutex_unlock(&ringbuf.lock); 319 ok = syncchan(_stream_fd, 320 INIT_SYNC_WINDOW_SIZE * TSPacket::SIZE, 321 INIT_MIN_NUM_SYNC_PACKETS); 322 SR_CHK("Failed to sync to transport stream to valid packet."); 322 323 323 pauseWait.wakeAll(); 324 if (tvrec) 325 tvrec->RecorderPaused(); 324 _drb->Start(); 326 325 327 usleep(1000);328 continue;329 }330 else if (paused)331 {332 pthread_mutex_lock(&ringbuf.lock);333 ringbuf.writePtr = ringbuf.readPtr = ringbuf.buffer;334 ringbuf.used = 0;335 ringbuf.paused = false;336 pthread_mutex_unlock(&ringbuf.lock);337 }338 339 contiguous = ringbuf.endPtr - ringbuf.writePtr;340 341 while (unused < TSPacket::SIZE && contiguous > TSPacket::SIZE)342 {343 usleep(500);344 345 pthread_mutex_lock(&ringbuf.lock);346 unused = ringbuf.size - ringbuf.used;347 request_pause = ringbuf.request_pause;348 pthread_mutex_unlock(&ringbuf.lock);349 350 if (request_pause)351 break;352 }353 if (request_pause)354 continue;355 356 read_size = unused > contiguous ? contiguous : unused;357 if (read_size > ringbuf.dev_read_size)358 read_size = ringbuf.dev_read_size;359 360 len = read(_stream_fd, ringbuf.writePtr, read_size);361 362 if (len < 0)363 {364 if (errno == EINTR)365 continue;366 367 VERBOSE(VB_IMPORTANT, QString("HD7 error reading from %1")368 .arg(videodevice));369 perror("read");370 if (++errcnt > 5)371 {372 pthread_mutex_lock(&ringbuf.lock);373 ringbuf.error = true;374 pthread_mutex_unlock(&ringbuf.lock);375 376 break;377 }378 379 usleep(500);380 continue;381 }382 else if (len == 0)383 {384 if (++errcnt > 5)385 {386 VERBOSE(VB_IMPORTANT, QString("HD8 %1 end of file found.")387 .arg(videodevice));388 389 pthread_mutex_lock(&ringbuf.lock);390 ringbuf.eof = true;391 pthread_mutex_unlock(&ringbuf.lock);392 393 break;394 }395 usleep(500);396 continue;397 }398 399 errcnt = 0;400 401 pthread_mutex_lock(&ringbuf.lock);402 ringbuf.used += len;403 used = ringbuf.used;404 ringbuf.writePtr += len;405 pthread_mutex_unlock(&ringbuf.lock);406 407 #ifdef REPORT_RING_STATS408 pthread_mutex_lock(&ringbuf.lock_stats);409 410 if (ringbuf.max_used < used)411 ringbuf.max_used = used;412 413 ringbuf.avg_used = ((ringbuf.avg_used * ringbuf.avg_cnt) + used)414 / ++ringbuf.avg_cnt;415 pthread_mutex_unlock(&ringbuf.lock_stats);416 #endif417 418 if (ringbuf.writePtr == ringbuf.endPtr)419 ringbuf.writePtr = ringbuf.buffer;420 }421 422 close(_stream_fd);423 _stream_fd = -1;424 }425 426 /* read count bytes from ring into buffer */427 int HDTVRecorder::ringbuf_read(unsigned char *buffer, size_t count)428 {429 size_t avail;430 size_t cnt = count;431 size_t min_read;432 unsigned char *cPtr = buffer;433 434 bool dev_error = false;435 bool dev_eof = false;436 437 pthread_mutex_lock(&ringbuf.lock);438 avail = ringbuf.used;439 pthread_mutex_unlock(&ringbuf.lock);440 441 min_read = cnt < ringbuf.min_read ? cnt : ringbuf.min_read;442 443 while (min_read > avail)444 {445 usleep(50000);446 447 if (request_pause || dev_error || dev_eof)448 return 0;449 450 pthread_mutex_lock(&ringbuf.lock);451 dev_error = ringbuf.error;452 dev_eof = ringbuf.eof;453 avail = ringbuf.used;454 pthread_mutex_unlock(&ringbuf.lock);455 }456 if (cnt > avail)457 cnt = avail;458 459 if (ringbuf.readPtr + cnt > ringbuf.endPtr)460 {461 size_t len;462 463 // Process as two pieces464 len = ringbuf.endPtr - ringbuf.readPtr;465 memcpy(cPtr, ringbuf.readPtr, len);466 cPtr += len;467 len = cnt - len;468 469 // Wrap arround to begining of buffer470 ringbuf.readPtr = ringbuf.buffer;471 memcpy(cPtr, ringbuf.readPtr, len);472 ringbuf.readPtr += len;473 }474 else475 {476 memcpy(cPtr, ringbuf.readPtr, cnt);477 ringbuf.readPtr += cnt;478 }479 480 pthread_mutex_lock(&ringbuf.lock);481 ringbuf.used -= cnt;482 pthread_mutex_unlock(&ringbuf.lock);483 484 if (ringbuf.readPtr == ringbuf.endPtr)485 ringbuf.readPtr = ringbuf.buffer;486 else487 {488 #ifdef REPORT_RING_STATS489 size_t samples, avg, max;490 491 if (++loop == report_loops)492 {493 loop = 0;494 pthread_mutex_lock(&ringbuf.lock_stats);495 avg = ringbuf.avg_used;496 samples = ringbuf.avg_cnt;497 max = ringbuf.max_used;498 ringbuf.avg_used = 0;499 ringbuf.avg_cnt = 0;500 ringbuf.max_used = 0;501 pthread_mutex_unlock(&ringbuf.lock_stats);502 503 VERBOSE(VB_IMPORTANT, QString("%1 ringbuf avg %2% max %3%"504 " samples %4")505 .arg(videodevice)506 .arg((static_cast<double>(avg)507 / ringbuf.size) * 100.0)508 .arg((static_cast<double>(max)509 / ringbuf.size) * 100.0)510 .arg(samples));511 }512 else513 #endif514 usleep(25);515 }516 517 return cnt;518 }519 520 void HDTVRecorder::StartRecording(void)521 {522 bool pause;523 bool dev_error, dev_eof;524 int len;525 526 const int unsyncpackets = 50; // unsynced packets to look at before giving up527 const int syncpackets = 10; // synced packets to require before starting recording528 529 VERBOSE(VB_RECORD, QString("StartRecording"));530 531 if (!Open())532 {533 _error = true;534 return;535 }536 537 326 _request_recording = true; 538 _recording = true;327 _recording = true; 539 328 540 // Setup device ringbuffer 541 delete[] ringbuf.buffer; 542 543 // ringbuf.size = 60 * 1024 * TSPacket::SIZE; 544 ringbuf.size = gContext->GetNumSetting("HDRingbufferSize", 50*188); 545 ringbuf.size *= 1024; 546 547 if ((ringbuf.buffer = 548 new unsigned char[ringbuf.size + TSPacket::SIZE]) == NULL) 329 // Process packets while recording is requested 330 while (_request_recording && !_error) 549 331 { 550 VERBOSE(VB_IMPORTANT, "Failed to allocate HDTVRecorder ring buffer."); 551 _error = true; 552 return; 553 } 554 555 memset(ringbuf.buffer, 0xFF, ringbuf.size + TSPacket::SIZE); 556 ringbuf.endPtr = ringbuf.buffer + ringbuf.size; 557 ringbuf.readPtr = ringbuf.writePtr = ringbuf.buffer; 558 ringbuf.dev_read_size = TSPacket::SIZE * 48; 559 ringbuf.min_read = TSPacket::SIZE * 4; 560 ringbuf.used = 0; 561 ringbuf.max_used = 0; 562 ringbuf.avg_used = 0; 563 ringbuf.avg_cnt = 0; 564 ringbuf.request_pause = false; 565 ringbuf.paused = false; 566 ringbuf.error = false; 567 ringbuf.eof = false; 568 569 VERBOSE(VB_RECORD, QString("HD ring buffer size %1 KB") 570 .arg(ringbuf.size/1024)); 571 572 // sync device stream so it starts with a valid ts packet 573 if (!syncchan(_stream_fd, TSPacket::SIZE*unsyncpackets, syncpackets)) 574 { 575 _error = true; 576 return; 577 } 578 579 // create thread to fill the ringbuffer 580 pthread_create(&ringbuf.thread, NULL, boot_ringbuffer, 581 reinterpret_cast<void *>(this)); 582 583 int remainder = 0; 584 // TRANSFER DATA 585 while (_request_recording) 586 { 587 pthread_mutex_lock(&ringbuf.lock); 588 dev_error = ringbuf.error; 589 dev_eof = ringbuf.eof; 590 pause = ringbuf.paused; 591 pthread_mutex_unlock(&ringbuf.lock); 592 593 if (request_pause) 594 { 595 pthread_mutex_lock(&ringbuf.lock); 596 ringbuf.request_pause = true; 597 pthread_mutex_unlock(&ringbuf.lock); 598 599 usleep(1000); 332 if (PauseAndWait()) 600 333 continue; 601 }602 else if (pause)603 {604 pthread_mutex_lock(&ringbuf.lock);605 ringbuf.request_pause = false;606 pthread_mutex_unlock(&ringbuf.lock);607 334 608 usleep(1500); 609 continue; 610 } 335 len = _drb->Read(&(_buffer[remainder]), _buffer_size - remainder); 611 336 612 if (dev_error)613 {614 VERBOSE(VB_IMPORTANT, "HDTV: device error detected");615 _error = true;616 break;617 }618 619 if (dev_eof)620 break;621 622 len = ringbuf_read(&(_buffer[remainder]), _buffer_size - remainder);623 624 337 if (len == 0) 625 338 continue; 626 339 627 340 len += remainder; 628 remainder = ProcessData (_buffer, len);341 remainder = ProcessDataTS(_buffer, len); 629 342 if (remainder > 0) // leftover bytes 630 343 memmove(_buffer, &(_buffer[_buffer_size - remainder]), 631 344 remainder); 345 346 // Check for DRB errors 347 if (_drb->IsErrored()) 348 { 349 VERBOSE(VB_IMPORTANT, LOC_ERR + "Device error detected"); 350 _error = true; 351 } 352 353 if (_drb->IsEOF()) 354 { 355 VERBOSE(VB_IMPORTANT, LOC_ERR + "Device EOF detected"); 356 _error = true; 357 } 632 358 } 633 359 634 360 FinishRecording(); 635 361 _recording = false; 636 362 } 363 #undef SR_CHK 637 364 638 365 void HDTVRecorder::StopRecording(void) 639 366 { … … 649 376 650 377 _request_recording = false; 651 378 652 pthread_mutex_lock(&ringbuf.lock); 653 bool run = ringbuf.run; 654 ringbuf.run = false; 655 pthread_mutex_unlock(&ringbuf.lock); 379 if (_drb && _drb->IsRunning()) 380 _drb->Stop(); 656 381 657 if (run)658 pthread_join(ringbuf.thread, NULL);382 while (_recording) 383 usleep(2000); 659 384 660 if (!ok)661 {662 // Better to have a memory leak, then a segfault?663 VERBOSE(VB_IMPORTANT, "DTV ringbuffer not cleaned up!\n");664 }665 else666 {667 delete[] ringbuf.buffer;668 ringbuf.buffer = 0;669 }670 385 tvrec = rec; 671 386 } 672 387 673 void HDTVRecorder:: Pause(bool /*clear*/)388 void HDTVRecorder::ReaderPaused(int /*fd*/) 674 389 { 675 pthread_mutex_lock(&ringbuf.lock); 676 ringbuf.paused = false; 677 pthread_mutex_unlock(&ringbuf.lock); 678 request_pause = true; 390 pauseWait.wakeAll(); 391 if (tvrec) 392 tvrec->RecorderPaused(); 679 393 } 680 394 681 bool HDTVRecorder:: IsPaused(void) const395 bool HDTVRecorder::PauseAndWait(int timeout) 682 396 { 683 pthread_mutex_lock(&ringbuf.lock); 684 bool paused = ringbuf.paused; 685 pthread_mutex_unlock(&ringbuf.lock); 397 #ifdef USE_DRB 398 if (request_pause) 399 { 400 paused = true; 401 if (!_drb->IsPaused()) 402 _drb->SetRequestPause(true); 686 403 404 unpauseWait.wait(timeout); 405 } 406 else if (_drb->IsPaused()) 407 { 408 _drb->SetRequestPause(false); 409 _drb->WaitForUnpause(timeout); 410 paused = _drb->IsPaused(); 411 } 412 else 413 { 414 paused = false; 415 } 687 416 return paused; 417 #else // if !USE_DRB 418 return RecorderBase::PauseAndWait(timeout); 419 #endif // !USE_DRB 688 420 } 689 421 690 422 int HDTVRecorder::ResyncStream(unsigned char *buffer, int curr_pos, int len) … … 695 427 if (nextpos >= len) 696 428 return -1; // not enough bytes; caller should try again 697 429 698 while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE) { 430 while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE) 431 { 699 432 pos++; 700 433 nextpos++; 701 434 if (nextpos == len) … … 707 440 708 441 void HDTVRecorder::WritePAT(ProgramAssociationTable *pat) 709 442 { 443 if (!pat) 444 return; 445 710 446 int next = (pat->tsheader()->ContinuityCounter()+1)&0xf; 711 447 pat->tsheader()->SetContinuityCounter(next); 712 448 ringBuffer->Write(pat->tsheader()->data(), TSPacket::SIZE); 713 449 } 714 450 715 #if WHACK_A_BUG_VIDEO716 static int WABV_base_pid = 0x100;717 #define WABV_WAIT 60718 static int WABV_wait_a_while = WABV_WAIT;719 bool WABV_started = false;720 #endif721 722 #if WHACK_A_BUG_AUDIO723 static int WABA_base_pid = 0x200;724 #define WABA_WAIT 60725 static int WABA_wait_a_while = WABA_WAIT;726 bool WABA_started = false;727 #endif728 729 451 void HDTVRecorder::WritePMT(ProgramMapTable* pmt) 730 452 { 731 if (pmt) { 732 int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf; 733 pmt->tsheader()->SetContinuityCounter(next); 453 if (!pmt) 454 return; 734 455 735 #if WHACK_A_BUG_VIDEO 736 WABV_wait_a_while--; 737 if (WABV_wait_a_while<=0) { 738 WABV_started = true; 739 WABV_wait_a_while = WABV_WAIT; 740 WABV_base_pid = (((WABV_base_pid-0x100)+1)%32)+0x100; 741 if (StreamID::MPEG2Video != StreamData()->PMT()->StreamType(0)) 742 { 743 VERBOSE(VB_IMPORTANT, "HDTVRecorder::WritePMT(): Error," 744 "Whack a Bug can not rewrite PMT, wrong stream type"); 745 } 746 else 747 { 748 VERBOSE(VB_IMPORTANT, QString("Whack a Bug: new video pid %1"). 749 arg(WABV_base_pid)); 750 // rewrite video pid 751 const uint old_video_pid=StreamData()->PMT()->StreamPID(0); 752 StreamData()->PMT()->SetStreamPID(0, WABV_base_pid); 753 if (StreamData()->PMT()->PCRPID() == old_video_pid) 754 StreamData()->PMT()->SetPCRPID(WABV_base_pid); 755 StreamData()->PMT()->SetCRC(StreamData()->PMT()->CalcCRC()); 756 VERBOSE(VB_IMPORTANT, StreamData()->PMT()->toString()); 757 } 758 } 759 #endif 760 #if WHACK_A_BUG_AUDIO 761 WABA_wait_a_while--; 762 if (WABA_wait_a_while<=0) { 763 WABA_started = true; 764 WABA_wait_a_while = WABA_WAIT; 765 WABA_base_pid = (((WABA_base_pid-0x200)+1)%32)+0x200; 766 VERBOSE(VB_IMPORTANT, QString("Whack a Bug: new audio BASE pid %1").arg(WABA_base_pid)); 767 // rewrite audio pids 768 for (uint i=0; i<StreamData()->PMT()->StreamCount(); i++) { 769 if (StreamID::MPEG2Audio == StreamData()->PMT()->StreamType(i) || 770 StreamID::MPEG2Audio == StreamData()->PMT()->StreamType(i)) { 771 const uint old_audio_pid = StreamData()->PMT()->StreamPID(i); 772 const uint new_audio_pid = WABA_base_pid + old_audio_pid; 773 StreamData()->PMT()->SetStreamPID(i, new_audio_pid); 774 if (StreamData()->PMT()->PCRPID() == old_audio_pid) 775 StreamData()->PMT()->SetPCRPID(new_audio_pid); 776 StreamData()->PMT()->SetCRC(StreamData()->PMT()->CalcCRC()); 777 VERBOSE(VB_IMPORTANT, StreamData()->PMT()->toString()); 778 } 779 } 780 } 781 #endif 782 783 ringBuffer->Write(pmt->tsheader()->data(), TSPacket::SIZE); 784 } 456 int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf; 457 pmt->tsheader()->SetContinuityCounter(next); 458 ringBuffer->Write(pmt->tsheader()->data(), TSPacket::SIZE); 785 459 } 786 460 787 461 /** \fn HDTVRecorder::ProcessMGT(const MasterGuideTable*) … … 820 494 { 821 495 if (vct->ProgramNumber(i) != (uint)StreamData()->DesiredProgram()) 822 496 { 823 VERBOSE(VB_RECORD, 824 QString("Resetting desired program from %1" 825 " to %2") 497 VERBOSE(VB_RECORD, LOC_ERR + 498 QString("Resetting desired program from %1 to %2") 826 499 .arg(StreamData()->DesiredProgram()) 827 500 .arg(vct->ProgramNumber(i))); 828 501 // Do a (partial?) reset here if old desired … … 834 507 } 835 508 if (!found) 836 509 { 837 VERBOSE(VB_IMPORTANT, 510 VERBOSE(VB_IMPORTANT, LOC_ERR + 838 511 QString("Desired channel %1_%2 not found;" 839 512 " using %3_%4 instead.") 840 513 .arg(StreamData()->DesiredMajorChannel()) 841 514 .arg(StreamData()->DesiredMinorChannel()) 842 515 .arg(vct->MajorChannel(0)) 843 .arg(vct->MinorChannel(0)) );844 VERBOSE(VB_IMPORTANT, vct->toString()); 516 .arg(vct->MinorChannel(0)) + "\n" + vct->toString()); 517 845 518 StreamData()->SetDesiredProgram(vct->ProgramNumber(0)); 846 519 } 847 520 } … … 854 527 if (_wait_for_keyframe && !_keyframe_seen) 855 528 return; 856 529 857 #if WHACK_A_BUG_VIDEO858 if (WABV_started)859 ((TSPacket*)(tspacket))->SetPID(WABV_base_pid);860 #endif861 862 530 ringBuffer->Write(tspacket->data(), TSPacket::SIZE); 863 531 } 864 532 … … 868 536 if (_wait_for_keyframe && !_keyframe_seen) 869 537 return; 870 538 871 #if WHACK_A_BUG_AUDIO872 if (WABA_started)873 ((TSPacket*)(tspacket))->SetPID(WABA_base_pid+tspacket->PID());874 #endif875 876 539 ringBuffer->Write(tspacket->data(), TSPacket::SIZE); 877 540 } 878 541 … … 902 565 return ok; 903 566 } 904 567 905 int HDTVRecorder::ProcessData(unsigned char *buffer,int len)568 uint HDTVRecorder::ProcessDataTS(unsigned char *buffer, uint len) 906 569 { 907 int pos = 0; 570 if (len < TSPacket::SIZE) 571 return len; 908 572 909 while (pos + 187 < len) // while we have a whole packet left 573 uint pos = 0; 574 uint end = len - TSPacket::SIZE; 575 while (pos <= end) // while we have a whole packet left 910 576 { 911 577 if (buffer[pos] != SYNC_BYTE) 912 578 { 913 579 _resync_count++; 914 if (25 == _resync_count) 915 VERBOSE(VB_RECORD, QString("Resyncing many of times, suppressing error messages")); 580 581 if (25 == _resync_count) 582 { 583 VERBOSE(VB_RECORD, LOC + "Resyncing many of times, " 584 "suppressing error messages"); 585 } 916 586 else if (25 > _resync_count) 917 VERBOSE(VB_RECORD, QString("Resyncing")); 587 { 588 VERBOSE(VB_RECORD, LOC + "Resyncing"); 589 } 590 918 591 int newpos = ResyncStream(buffer, pos, len); 919 592 if (newpos == -1) 920 593 return len - pos; … … 925 598 } 926 599 927 600 const TSPacket *pkt = reinterpret_cast<const TSPacket*>(&buffer[pos]); 928 if (ProcessTSPacket(*pkt)) { 929 pos += TSPacket::SIZE; // Advance to next TS packet 601 if (ProcessTSPacket(*pkt)) 602 { 603 // Advance to next TS packet 604 pos += TSPacket::SIZE; 605 606 // Take care of statistics 930 607 _ts_stats.IncrTSPacketCount(); 931 if (0 == _ts_stats.TSPacketCount()%1000000) 932 VERBOSE(VB_RECORD, _ts_stats.toString()); 933 } else // Let it resync in case of dropped bytes 934 buffer[pos] = SYNC_BYTE+1; 608 if (0 == _ts_stats.TSPacketCount() % 1000000) 609 VERBOSE(VB_RECORD, LOC + "\n" + _ts_stats.toString()); 610 611 } 612 else 613 { 614 pos++; // Resync on invalid packet, in case of dropped bytes... 615 } 935 616 } 936 617 937 618 return len - pos; … … 939 620 940 621 void HDTVRecorder::Reset(void) 941 622 { 942 VERBOSE(VB_RECORD, "HDTVRecorder::Reset(void)");623 VERBOSE(VB_RECORD, LOC + "Reset(void)"); 943 624 DTVRecorder::Reset(); 944 625 945 626 _error = false; … … 947 628 _ts_stats.Reset(); 948 629 949 630 if (curRecording) 950 {951 631 curRecording->ClearPositionMap(MARK_GOP_BYFRAME); 632 633 if (!IsOpen()) 634 return /* true */; 635 636 if (!IsPaused()) 637 { 638 Pause(); 639 WaitForPause(); 952 640 } 953 641 954 if (_stream_fd >= 0) 642 if (!Close()) 643 return /* false */; 644 645 if (Open()) 955 646 { 956 if (!IsPaused()) 957 { 958 Pause(); 959 WaitForPause(); 960 } 961 int ret = close(_stream_fd); 962 if (ret < 0) 963 { 964 perror("close"); 965 return; 966 } 967 #if FAKE_VIDEO 968 // open file instead of device 969 _stream_fd = open(FAKE_VIDEO_FILES[fake_video_index], O_RDWR); 970 VERBOSE(VB_IMPORTANT, QString("Opened fake video source %1").arg(FAKE_VIDEO_FILES[fake_video_index])); 971 fake_video_index = (fake_video_index+1)%FAKE_VIDEO_NUM; 972 #else 973 _stream_fd = open(videodevice.ascii(), O_RDWR); 974 #endif 975 if (_stream_fd < 0) 976 { 977 VERBOSE(VB_IMPORTANT, QString("HD1 Can't open video device: %1 chanfd = %2"). 978 arg(videodevice).arg(_stream_fd)); 979 perror("open video"); 980 return; 981 } 982 else 983 { 984 pthread_mutex_lock(&ringbuf.lock); 985 ringbuf.used = 0; 986 ringbuf.max_used = 0; 987 ringbuf.readPtr = ringbuf.writePtr = ringbuf.buffer; 988 pthread_mutex_unlock(&ringbuf.lock); 989 } 647 _drb->Reset(videodevice, _stream_fd); 990 648 Unpause(); 649 return /* true */; 991 650 } 651 652 VERBOSE(VB_IMPORTANT, LOC_ERR + "Couldn't open video device: " + 653 QString("'%1'").arg(videodevice) + ENO); 654 return /* false */; 992 655 }