Skip to content

Commit

Permalink
Fixes #9830. Refs #10519. Fixes channel change on PVR350.
Browse files Browse the repository at this point in the history
The drivers for some V4L devices require you to explicitly stop and restart streaming when sending certain ioctl's to the device. We already pause and unpause the recorder when issuing these commands so this adds a close(readfd) to the code that is run on pause and reopens readfd on the unpause code. This also means the DeviceReadBuffer needs to be reset with the new readfd, so we do that as well.
  • Loading branch information
daniel-kristjansson committed Apr 5, 2012
1 parent 0b7d424 commit a87ad95
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 76 deletions.
118 changes: 44 additions & 74 deletions mythtv/libs/libmythtv/mpegrecorder.cpp
Expand Up @@ -968,14 +968,7 @@ void MpegRecorder::run(void)
else if (_device_read_buffer)
{
LOG(VB_RECORD, LOG_INFO, LOC + "Initial startup of recorder");

if (!StartEncoding(readfd))
{
LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to start recording");
_error = "Failed to start recording";
}
else
_device_read_buffer->Start();
StartEncoding();
}

QByteArray vdevice = videodevice.toAscii();
Expand Down Expand Up @@ -1005,25 +998,6 @@ void MpegRecorder::run(void)
}
}
}
else
{
if (readfd < 0)
{
if (!Open())
{
_error = "Failed to open device";
break;
}

if (readfd < 0)
{
LOG(VB_GENERAL, LOG_ERR, LOC +
QString("Failed to open device '%1'")
.arg(videodevice));
continue;
}
}
}

if (_device_read_buffer)
{
Expand Down Expand Up @@ -1138,18 +1112,7 @@ void MpegRecorder::run(void)

LOG(VB_RECORD, LOG_INFO, LOC + "run finishing up");

pauseLock.lock();
if (_device_read_buffer)
{
if (_device_read_buffer->IsRunning())
_device_read_buffer->Stop();

delete _device_read_buffer;
_device_read_buffer = NULL;
}
pauseLock.unlock();

StopEncoding(readfd);
StopEncoding();

{
QMutexLocker locker(&pauseLock);
Expand Down Expand Up @@ -1183,10 +1146,7 @@ void MpegRecorder::run(void)

void MpegRecorder::StopRecording(void)
{
pauseLock.lock();
if (_device_read_buffer && _device_read_buffer->IsRunning())
_device_read_buffer->Stop();
pauseLock.unlock();
MpegRecorder::StopEncoding();
V4LRecorder::StopRecording();
}

Expand Down Expand Up @@ -1246,13 +1206,7 @@ bool MpegRecorder::PauseAndWait(int timeout)
{
LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait pause");

if (_device_read_buffer)
{
_device_read_buffer->SetRequestPause(true);
_device_read_buffer->WaitForPaused(4000);
}

StopEncoding(readfd);
StopEncoding();

paused = true;
pauseWait.wakeAll();
Expand All @@ -1277,10 +1231,7 @@ bool MpegRecorder::PauseAndWait(int timeout)
SetV4L2DeviceOptions(chanfd);
}

StartEncoding(readfd);

if (_device_read_buffer)
_device_read_buffer->SetRequestPause(false);
StartEncoding();

if (_stream_data)
_stream_data->Reset(_stream_data->DesiredProgram());
Expand All @@ -1295,11 +1246,9 @@ void MpegRecorder::RestartEncoding(void)
{
LOG(VB_RECORD, LOG_INFO, LOC + "RestartEncoding");

_device_read_buffer->Stop();

QMutexLocker locker(&start_stop_encoding_lock);

StopEncoding(readfd);
StopEncoding();

// Make sure the next things in the file are a PAT & PMT
if (_stream_data &&
Expand All @@ -1313,19 +1262,11 @@ void MpegRecorder::RestartEncoding(void)

if (driver == "hdpvr") // HD-PVR will sometimes reset to defaults
SetV4L2DeviceOptions(chanfd);
if (!StartEncoding(readfd))
{
if (0 != close(readfd))
LOG(VB_GENERAL, LOG_ERR, LOC + "Close error" + ENO);

readfd = -1;
return;
}

_device_read_buffer->Start();
StartEncoding();
}

bool MpegRecorder::StartEncoding(int fd)
bool MpegRecorder::StartEncoding(void)
{
QMutexLocker locker(&start_stop_encoding_lock);

Expand All @@ -1338,7 +1279,19 @@ bool MpegRecorder::StartEncoding(int fd)

LOG(VB_RECORD, LOG_INFO, LOC + "StartEncoding");

bool started = 0 == ioctl(fd, VIDIOC_ENCODER_CMD, &command);
if (readfd < 0)
{
readfd = open(videodevice.toAscii().constData(), O_RDWR | O_NONBLOCK);
if (readfd < 0)
{
LOG(VB_GENERAL, LOG_ERR, LOC +
"StartEncoding: Can't open video device." + ENO);
_error = "Failed to start recording";
return false;
}
}

bool started = 0 == ioctl(readfd, VIDIOC_ENCODER_CMD, &command);
if (started)
{
if (driver == "hdpvr")
Expand All @@ -1362,21 +1315,30 @@ bool MpegRecorder::StartEncoding(int fd)
LOG(VB_GENERAL, LOG_WARNING, LOC + "StartEncoding failed" + ENO);
}

return started;
if (_device_read_buffer)
{
_device_read_buffer->Reset(videodevice.toAscii().constData(), readfd);
_device_read_buffer->Start();
}

return true;
}

bool MpegRecorder::StopEncoding(int fd)
void MpegRecorder::StopEncoding(void)
{
QMutexLocker locker(&start_stop_encoding_lock);

LOG(VB_RECORD, LOG_INFO, LOC + "StopEncoding");

if (readfd < 0)
return;

struct v4l2_encoder_cmd command;
memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
command.cmd = V4L2_ENC_CMD_STOP;
command.flags = V4L2_ENC_CMD_STOP_AT_GOP_END;

LOG(VB_RECORD, LOG_INFO, LOC + "StopEncoding");

bool stopped = 0 == ioctl(fd, VIDIOC_ENCODER_CMD, &command);
bool stopped = 0 == ioctl(readfd, VIDIOC_ENCODER_CMD, &command);
if (stopped)
{
LOG(VB_RECORD, LOG_INFO, LOC + "Encoding stopped");
Expand All @@ -1393,7 +1355,15 @@ bool MpegRecorder::StopEncoding(int fd)
LOG(VB_GENERAL, LOG_WARNING, LOC + "StopEncoding failed" + ENO);
}

return stopped;
if (_device_read_buffer && _device_read_buffer->IsRunning())
{
usleep(20 * 1000); // allow last bits of data through..
_device_read_buffer->Stop();
}

// close the fd so streamoff/streamon work in V4LChannel
close(readfd);
readfd = -1;
}

void MpegRecorder::SetStreamData(void)
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/mpegrecorder.h
Expand Up @@ -68,8 +68,8 @@ class MpegRecorder : public V4LRecorder,
uint GetFilteredAudioBitRate(uint audio_layer) const;

void RestartEncoding(void);
bool StartEncoding(int fd);
bool StopEncoding(int fd);
bool StartEncoding(void);
void StopEncoding(void);

void SetBitrate(int bitrate, int maxbitrate, const QString & reason);
void HandleResolutionChanges(void);
Expand Down

0 comments on commit a87ad95

Please sign in to comment.