|
MythTV
0.26-pre
|
00001 // -*- Mode: c++ -*- 00008 #include <unistd.h> 00009 00010 // MythTV headers 00011 #include "mpegstreamdata.h" 00012 #include "tspacket.h" 00013 #include "iptvchannel.h" 00014 #include "iptvfeederwrapper.h" 00015 #include "iptvrecorder.h" 00016 #include "tv_rec.h" 00017 00018 #define LOC QString("IPTVRec: ") 00019 00020 // ============================================================================ 00021 // IPTVRecorder : Processes data from RTSPComms and writes it to disk 00022 // ============================================================================ 00023 00024 IPTVRecorder::IPTVRecorder(TVRec *rec, IPTVChannel *channel) : 00025 DTVRecorder(rec), 00026 _channel(channel) 00027 { 00028 _channel->GetFeeder()->AddListener(this); 00029 } 00030 00031 IPTVRecorder::~IPTVRecorder() 00032 { 00033 StopRecording(); 00034 _channel->GetFeeder()->RemoveListener(this); 00035 } 00036 00037 bool IPTVRecorder::Open(void) 00038 { 00039 LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- begin"); 00040 00041 if (_channel->GetFeeder()->IsOpen()) 00042 return true; // already open 00043 00044 IPTVChannelInfo chaninfo = _channel->GetCurrentChanInfo(); 00045 00046 if (!chaninfo.isValid()) 00047 _error = "Channel Info is invalid"; 00048 else if (!_channel->GetFeeder()->Open(chaninfo.m_url)) 00049 _error = QString("Failed to open URL %1") 00050 .arg(chaninfo.m_url); 00051 00052 LOG(VB_RECORD, LOG_INFO, LOC + QString("Open() -- end err(%1)") 00053 .arg(_error)); 00054 00055 return !IsErrored(); 00056 } 00057 00058 void IPTVRecorder::Close(void) 00059 { 00060 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin"); 00061 _channel->GetFeeder()->Stop(); 00062 _channel->GetFeeder()->Close(); 00063 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); 00064 } 00065 00066 void IPTVRecorder::StopRecording(void) 00067 { 00068 pauseLock.lock(); 00069 request_recording = false; 00070 unpauseWait.wakeAll(); 00071 pauseLock.unlock(); 00072 00073 // we can't hold the pause lock while we wait for the IPTV feeder to stop 00074 _channel->GetFeeder()->Stop(); 00075 } 00076 00077 void IPTVRecorder::run(void) 00078 { 00079 LOG(VB_RECORD, LOG_INFO, LOC + "run() -- begin"); 00080 if (!Open()) 00081 { 00082 _error = "Failed to open IPTV stream"; 00083 return; 00084 } 00085 00086 // Start up... 00087 { 00088 QMutexLocker locker(&pauseLock); 00089 request_recording = true; 00090 recording = true; 00091 recordingWait.wakeAll(); 00092 } 00093 00094 // Go into main RTSP loop, feeding data to AddData 00095 _channel->GetFeeder()->Run(); 00096 00097 Close(); 00098 00099 // Finish up... 00100 FinishRecording(); 00101 QMutexLocker locker(&pauseLock); 00102 recording = false; 00103 recordingWait.wakeAll(); 00104 00105 LOG(VB_RECORD, LOG_INFO, LOC + "run() -- end"); 00106 } 00107 00108 // =================================================== 00109 // findTSHeader : find a TS Header in flow 00110 // =================================================== 00111 static int IPTVRecorder_findTSHeader(const unsigned char *data, 00112 uint dataSize) 00113 { 00114 unsigned int pos = 0; 00115 00116 while (pos < dataSize) 00117 { 00118 if (data[pos] == 0x47) 00119 return pos; 00120 pos++; 00121 } 00122 00123 return -1; 00124 } 00125 00126 // =================================================== 00127 // AddData : feed data from RTSP flow to mythtv 00128 // =================================================== 00129 void IPTVRecorder::AddData(const unsigned char *data, unsigned int dataSize) 00130 { 00131 unsigned int readIndex = 0; 00132 00133 // data may be compose from more than one packet, loop to consume all data 00134 while (readIndex < dataSize) 00135 { 00136 // If recorder is paused, stop there 00137 if (IsPaused(false)) 00138 return; 00139 00140 // Find the next TS Header in data 00141 int tsPos = IPTVRecorder_findTSHeader( 00142 data + readIndex, dataSize - readIndex); 00143 00144 // if no TS, something bad happens 00145 if (tsPos == -1) 00146 { 00147 LOG(VB_GENERAL, LOG_ERR, LOC + "No TS header."); 00148 break; 00149 } 00150 00151 // if TS Header not at start of data, we receive out of sync data 00152 if (tsPos > 0) 00153 { 00154 LOG(VB_GENERAL, LOG_ERR, LOC + 00155 QString("TS packet at %1, not in sync.").arg(tsPos)); 00156 } 00157 00158 // Check if the next packet in buffer is complete : 00159 // packet size is 188 bytes long 00160 if ((dataSize - tsPos - readIndex) < TSPacket::kSize) 00161 { 00162 LOG(VB_GENERAL, LOG_ERR, LOC + 00163 "TS packet at stradles end of buffer."); 00164 break; 00165 } 00166 00167 // Cast current found TS Packet to TSPacket structure 00168 const void *newData = data + tsPos + readIndex; 00169 ProcessTSPacket(*reinterpret_cast<const TSPacket*>(newData)); 00170 00171 // follow to next packet 00172 readIndex += tsPos + TSPacket::kSize; 00173 } 00174 } 00175 00176 bool IPTVRecorder::ProcessTSPacket(const TSPacket& tspacket) 00177 { 00178 if (!_stream_data) 00179 return true; 00180 00181 if (tspacket.TransportError() || tspacket.Scrambled()) 00182 return true; 00183 00184 if (tspacket.HasAdaptationField()) 00185 _stream_data->HandleAdaptationFieldControl(&tspacket); 00186 00187 if (tspacket.HasPayload()) 00188 { 00189 const unsigned int lpid = tspacket.PID(); 00190 00191 // Pass or reject packets based on PID, and parse info from them 00192 if (lpid == _stream_data->VideoPIDSingleProgram()) 00193 { 00194 ProgramMapTable *pmt = _stream_data->PMTSingleProgram(); 00195 uint video_stream_type = pmt->StreamType(pmt->FindPID(lpid)); 00196 00197 if (video_stream_type == StreamID::H264Video) 00198 _buffer_packets = !FindH264Keyframes(&tspacket); 00199 else if (StreamID::IsVideo(video_stream_type)) 00200 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 00201 00202 if ((video_stream_type != StreamID::H264Video) || _seen_sps) 00203 BufferedWrite(tspacket); 00204 } 00205 else if (_stream_data->IsAudioPID(lpid)) 00206 { 00207 _buffer_packets = !FindAudioKeyframes(&tspacket); 00208 BufferedWrite(tspacket); 00209 } 00210 else if (_stream_data->IsListeningPID(lpid)) 00211 _stream_data->HandleTSTables(&tspacket); 00212 else if (_stream_data->IsWritingPID(lpid)) 00213 BufferedWrite(tspacket); 00214 } 00215 00216 return true; 00217 } 00218 00219 void IPTVRecorder::SetStreamData(void) 00220 { 00221 _stream_data->AddMPEGSPListener(this); 00222 } 00223 00224 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1