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 #include "tv_rec.h"
00017
00018 #define LOC QString("IPTVRec: ")
00019
00020
00021
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;
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
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
00087 {
00088 QMutexLocker locker(&pauseLock);
00089 request_recording = true;
00090 recording = true;
00091 recordingWait.wakeAll();
00092 }
00093
00094
00095 _channel->GetFeeder()->Run();
00096
00097 Close();
00098
00099
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
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
00128
00129 void IPTVRecorder::AddData(const unsigned char *data, unsigned int dataSize)
00130 {
00131 unsigned int readIndex = 0;
00132
00133
00134 while (readIndex < dataSize)
00135 {
00136
00137 if (IsPaused(false))
00138 return;
00139
00140
00141 int tsPos = IPTVRecorder_findTSHeader(
00142 data + readIndex, dataSize - readIndex);
00143
00144
00145 if (tsPos == -1)
00146 {
00147 LOG(VB_GENERAL, LOG_ERR, LOC + "No TS header.");
00148 break;
00149 }
00150
00151
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
00159
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
00168 const void *newData = data + tsPos + readIndex;
00169 ProcessTSPacket(*reinterpret_cast<const TSPacket*>(newData));
00170
00171
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
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