00001
00008 #include <unistd.h>
00009
00010
00011 #include "mpegstreamdata.h"
00012 #include "tspacket.h"
00013 #include "iptvchannel.h"
00014 #include "iptvfeederwrapper.h"
00015 #include "iptvrecorder.h"
00016
00017 #define LOC QString("IPTVRec: ")
00018 #define LOC_ERR QString("IPTVRec, Error: ")
00019
00020
00021
00022
00023
00024 IPTVRecorder::IPTVRecorder(TVRec *rec, IPTVChannel *channel) :
00025 DTVRecorder(rec),
00026 _channel(channel),
00027 _stream_data(NULL)
00028 {
00029 _channel->GetFeeder()->AddListener(this);
00030 }
00031
00032 IPTVRecorder::~IPTVRecorder()
00033 {
00034 StopRecording();
00035 _channel->GetFeeder()->RemoveListener(this);
00036 }
00037
00038 bool IPTVRecorder::Open(void)
00039 {
00040 VERBOSE(VB_RECORD, LOC + "Open() -- begin");
00041
00042 if (_channel->GetFeeder()->IsOpen())
00043 _channel->GetFeeder()->Close();
00044
00045 IPTVChannelInfo chaninfo = _channel->GetCurrentChanInfo();
00046 _error = (!chaninfo.isValid() ||
00047 !_channel->GetFeeder()->Open(chaninfo.m_url));
00048
00049 VERBOSE(VB_RECORD, LOC + "Open() -- end err("<<_error<<")");
00050 return !_error;
00051 }
00052
00053 void IPTVRecorder::Close(void)
00054 {
00055 VERBOSE(VB_RECORD, LOC + "Close() -- begin");
00056 _channel->GetFeeder()->Stop();
00057 _channel->GetFeeder()->Close();
00058 VERBOSE(VB_RECORD, LOC + "Close() -- end");
00059 }
00060
00061 void IPTVRecorder::Pause(bool clear)
00062 {
00063 VERBOSE(VB_RECORD, LOC + "Pause() -- begin");
00064 DTVRecorder::Pause(clear);
00065 _channel->GetFeeder()->Stop();
00066 _channel->GetFeeder()->Close();
00067 VERBOSE(VB_RECORD, LOC + "Pause() -- end");
00068 }
00069
00070 void IPTVRecorder::Unpause(void)
00071 {
00072 VERBOSE(VB_RECORD, LOC + "Unpause() -- begin");
00073
00074 if (_recording && !_channel->GetFeeder()->IsOpen())
00075 Open();
00076
00077 if (_stream_data)
00078 _stream_data->Reset(_stream_data->DesiredProgram());
00079
00080 DTVRecorder::Unpause();
00081
00082 VERBOSE(VB_RECORD, LOC + "Unpause() -- end");
00083 }
00084
00085 void IPTVRecorder::StartRecording(void)
00086 {
00087 VERBOSE(VB_RECORD, LOC + "StartRecording() -- begin");
00088 if (!Open())
00089 {
00090 _error = true;
00091 return;
00092 }
00093
00094
00095 _recording = true;
00096 _request_recording = true;
00097
00098 while (_request_recording)
00099 {
00100 if (PauseAndWait())
00101 continue;
00102
00103 if (!_channel->GetFeeder()->IsOpen())
00104 {
00105 usleep(5000);
00106 continue;
00107 }
00108
00109
00110 _channel->GetFeeder()->Run();
00111 }
00112
00113
00114 FinishRecording();
00115 Close();
00116
00117 VERBOSE(VB_RECORD, LOC + "StartRecording() -- end");
00118 _recording = false;
00119 _cond_recording.wakeAll();
00120 }
00121
00122 void IPTVRecorder::StopRecording(void)
00123 {
00124 VERBOSE(VB_RECORD, LOC + "StopRecording() -- begin");
00125 Pause();
00126 _channel->GetFeeder()->Close();
00127
00128 _request_recording = false;
00129 while (_recording)
00130 _cond_recording.wait(500);
00131
00132 VERBOSE(VB_RECORD, LOC + "StopRecording() -- end");
00133 }
00134
00135
00136
00137
00138 static int IPTVRecorder_findTSHeader(const unsigned char *data,
00139 uint dataSize)
00140 {
00141 unsigned int pos = 0;
00142
00143 while (pos < dataSize)
00144 {
00145 if (data[pos] == 0x47)
00146 return pos;
00147 pos++;
00148 }
00149
00150 return -1;
00151 }
00152
00153
00154
00155
00156 void IPTVRecorder::AddData(const unsigned char *data, unsigned int dataSize)
00157 {
00158 unsigned int readIndex = 0;
00159
00160
00161 while (readIndex < dataSize)
00162 {
00163
00164 if (IsPaused())
00165 return;
00166
00167
00168 int tsPos = IPTVRecorder_findTSHeader(
00169 data + readIndex, dataSize - readIndex);
00170
00171
00172 if (tsPos == -1)
00173 {
00174 VERBOSE(VB_IMPORTANT, LOC_ERR + "No TS header.");
00175 break;
00176 }
00177
00178
00179 if (tsPos > 0)
00180 {
00181 VERBOSE(VB_IMPORTANT, LOC_ERR +
00182 QString("TS packet at %1, not in sync.").arg(tsPos));
00183 }
00184
00185
00186
00187 if ((dataSize - tsPos - readIndex) < TSPacket::SIZE)
00188 {
00189 VERBOSE(VB_IMPORTANT, LOC_ERR +
00190 "TS packet at stradles end of buffer.");
00191 break;
00192 }
00193
00194
00195 const void *newData = data + tsPos + readIndex;
00196 ProcessTSPacket(*reinterpret_cast<const TSPacket*>(newData));
00197
00198
00199 readIndex += tsPos + TSPacket::SIZE;
00200 }
00201 }
00202
00203 void IPTVRecorder::ProcessTSPacket(const TSPacket& tspacket)
00204 {
00205 if (!_stream_data)
00206 return;
00207
00208 if (tspacket.TransportError() || tspacket.ScramplingControl())
00209 return;
00210
00211 if (tspacket.HasAdaptationField())
00212 _stream_data->HandleAdaptationFieldControl(&tspacket);
00213
00214 if (tspacket.HasPayload())
00215 {
00216 const unsigned int lpid = tspacket.PID();
00217
00218
00219 if (lpid == _stream_data->VideoPIDSingleProgram())
00220 {
00221 ProgramMapTable *pmt = _stream_data->PMTSingleProgram();
00222 uint video_stream_type = pmt->StreamType(pmt->FindPID(lpid));
00223
00224 if (video_stream_type == StreamID::H264Video)
00225 _buffer_packets = !FindH264Keyframes(&tspacket);
00226 else if (StreamID::IsVideo(video_stream_type))
00227 _buffer_packets = !FindMPEG2Keyframes(&tspacket);
00228
00229 if ((video_stream_type != StreamID::H264Video) || _seen_sps)
00230 BufferedWrite(tspacket);
00231 }
00232 else if (_stream_data->IsAudioPID(lpid))
00233 {
00234 _buffer_packets = !FindAudioKeyframes(&tspacket);
00235 BufferedWrite(tspacket);
00236 }
00237 else if (_stream_data->IsListeningPID(lpid))
00238 _stream_data->HandleTSTables(&tspacket);
00239 else if (_stream_data->IsWritingPID(lpid))
00240 BufferedWrite(tspacket);
00241 }
00242 }
00243
00244 void IPTVRecorder::SetStreamData(MPEGStreamData *data)
00245 {
00246 VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- begin");
00247
00248 if (data == _stream_data)
00249 {
00250 VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 0");
00251
00252 return;
00253 }
00254
00255 MPEGStreamData *old_data = _stream_data;
00256 _stream_data = data;
00257 if (old_data)
00258 delete old_data;
00259
00260 if (data)
00261 data->AddMPEGSPListener(this);
00262
00263 VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 1");
00264 }
00265
00266 void IPTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
00267 {
00268 if (!pat)
00269 return;
00270
00271 int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
00272 pat->tsheader()->SetContinuityCounter(next);
00273 BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader())));
00274 }
00275
00276 void IPTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
00277 {
00278 if (!pmt)
00279 return;
00280
00281 int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
00282 pmt->tsheader()->SetContinuityCounter(next);
00283 BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader())));
00284 }
00285
00286