00001
00007
00008 #include "firewirerecorder.h"
00009 #include "firewirechannel.h"
00010 #include "mythlogging.h"
00011 #include "mpegtables.h"
00012 #include "mpegstreamdata.h"
00013 #include "tv_rec.h"
00014
00015 #define LOC QString("FireRecBase(%1): ").arg(channel->GetDevice())
00016
00017 FirewireRecorder::FirewireRecorder(TVRec *rec, FirewireChannel *chan) :
00018 DTVRecorder(rec),
00019 channel(chan), isopen(false)
00020 {
00021 }
00022
00023 FirewireRecorder::~FirewireRecorder()
00024 {
00025 Close();
00026 }
00027
00028 bool FirewireRecorder::Open(void)
00029 {
00030 if (!isopen)
00031 {
00032 isopen = channel->GetFirewireDevice()->OpenPort();
00033 ResetForNewFile();
00034 }
00035 return isopen;
00036 }
00037
00038 void FirewireRecorder::Close(void)
00039 {
00040 if (isopen)
00041 {
00042 channel->GetFirewireDevice()->ClosePort();
00043 isopen = false;
00044 }
00045 }
00046
00047 void FirewireRecorder::StartStreaming(void)
00048 {
00049 channel->GetFirewireDevice()->AddListener(this);
00050 }
00051
00052 void FirewireRecorder::StopStreaming(void)
00053 {
00054 channel->GetFirewireDevice()->RemoveListener(this);
00055 }
00056
00057 void FirewireRecorder::run(void)
00058 {
00059 LOG(VB_RECORD, LOG_INFO, LOC + "run");
00060
00061 if (!Open())
00062 {
00063 _error = "Failed to open firewire device";
00064 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
00065 return;
00066 }
00067
00068 {
00069 QMutexLocker locker(&pauseLock);
00070 request_recording = true;
00071 recording = true;
00072 recordingWait.wakeAll();
00073 }
00074
00075 StartStreaming();
00076
00077 while (IsRecordingRequested() && !IsErrored())
00078 {
00079 if (PauseAndWait())
00080 continue;
00081
00082 if (!IsRecordingRequested())
00083 break;
00084
00085 {
00086
00087 QMutexLocker locker(&pauseLock);
00088 if (!request_recording || request_pause)
00089 continue;
00090 unpauseWait.wait(&pauseLock, 1000);
00091 }
00092 }
00093
00094 StopStreaming();
00095 FinishRecording();
00096
00097 QMutexLocker locker(&pauseLock);
00098 recording = false;
00099 recordingWait.wakeAll();
00100 }
00101
00102 void FirewireRecorder::AddData(const unsigned char *data, uint len)
00103 {
00104 uint bufsz = buffer.size();
00105 if ((SYNC_BYTE == data[0]) && (TSPacket::kSize == len) &&
00106 (TSPacket::kSize > bufsz))
00107 {
00108 if (bufsz)
00109 buffer.clear();
00110
00111 ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data)));
00112 return;
00113 }
00114
00115 buffer.insert(buffer.end(), data, data + len);
00116 bufsz += len;
00117
00118 int sync_at = -1;
00119 for (uint i = 0; (i < bufsz) && (sync_at < 0); i++)
00120 {
00121 if (buffer[i] == SYNC_BYTE)
00122 sync_at = i;
00123 }
00124
00125 if (sync_at < 0)
00126 return;
00127
00128 if (bufsz < 30 * TSPacket::kSize)
00129 return;
00130
00131 while (sync_at + TSPacket::kSize < bufsz)
00132 {
00133 ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(
00134 &buffer[0] + sync_at)));
00135
00136 sync_at += TSPacket::kSize;
00137 }
00138
00139 buffer.erase(buffer.begin(), buffer.begin() + sync_at);
00140
00141 return;
00142 }
00143
00144 bool FirewireRecorder::ProcessTSPacket(const TSPacket &tspacket)
00145 {
00146 if (tspacket.TransportError())
00147 return true;
00148
00149 if (tspacket.Scrambled())
00150 return true;
00151
00152 if (tspacket.HasAdaptationField())
00153 GetStreamData()->HandleAdaptationFieldControl(&tspacket);
00154
00155 if (tspacket.HasPayload())
00156 {
00157 const unsigned int lpid = tspacket.PID();
00158
00159
00160 if (lpid == GetStreamData()->VideoPIDSingleProgram())
00161 {
00162 _buffer_packets = !FindMPEG2Keyframes(&tspacket);
00163 BufferedWrite(tspacket);
00164 }
00165 else if (GetStreamData()->IsAudioPID(lpid))
00166 {
00167 _buffer_packets = !FindAudioKeyframes(&tspacket);
00168 BufferedWrite(tspacket);
00169 }
00170 else if (GetStreamData()->IsListeningPID(lpid))
00171 GetStreamData()->HandleTSTables(&tspacket);
00172 else if (GetStreamData()->IsWritingPID(lpid))
00173 BufferedWrite(tspacket);
00174 }
00175
00176 return true;
00177 }
00178
00179 void FirewireRecorder::SetOptionsFromProfile(RecordingProfile *profile,
00180 const QString &videodev,
00181 const QString &audiodev,
00182 const QString &vbidev)
00183 {
00184 (void)videodev;
00185 (void)audiodev;
00186 (void)vbidev;
00187 (void)profile;
00188 }
00189
00190
00191 bool FirewireRecorder::PauseAndWait(int timeout)
00192 {
00193 QMutexLocker locker(&pauseLock);
00194 if (request_pause)
00195 {
00196 LOG(VB_RECORD, LOG_INFO, LOC +
00197 QString("PauseAndWait(%1) -- pause").arg(timeout));
00198 if (!IsPaused(true))
00199 {
00200 StopStreaming();
00201 paused = true;
00202 pauseWait.wakeAll();
00203 if (tvrec)
00204 tvrec->RecorderPaused();
00205 }
00206 unpauseWait.wait(&pauseLock, timeout);
00207 }
00208
00209 if (!request_pause && IsPaused(true))
00210 {
00211 LOG(VB_RECORD, LOG_INFO, LOC +
00212 QString("PauseAndWait(%1) -- unpause").arg(timeout));
00213 StartStreaming();
00214 unpauseWait.wakeAll();
00215 }
00216
00217 return IsPaused(true);
00218 }
00219
00220 void FirewireRecorder::SetStreamData(void)
00221 {
00222 _stream_data->AddMPEGSPListener(this);
00223
00224 if (_stream_data->DesiredProgram() >= 0)
00225 _stream_data->SetDesiredProgram(_stream_data->DesiredProgram());
00226 }