171 changes: 77 additions & 94 deletions mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@

// MythTV
#include "iso639.h"
#include "mythdvdbuffer.h"
#include "mythdvdplayer.h"
#include "avformatdecoderdvd.h"

#include "iso639.h"

// FFmpeg
extern "C" {
#include "libavcodec/avcodec.h"
}

#include <unistd.h> // for usleep()
// Std
#include <thread>

#define LOC QString("AFD_DVD: ")
#define LOC QString("DVDDec: ")

AvFormatDecoderDVD::AvFormatDecoderDVD(MythPlayer *Parent, const ProgramInfo &PGInfo, PlayerFlags Flags)
: AvFormatDecoder(Parent, PGInfo, Flags)
{
}

AvFormatDecoderDVD::~AvFormatDecoderDVD()
{
Expand All @@ -24,7 +30,7 @@ AvFormatDecoderDVD::~AvFormatDecoderDVD()
ReleaseLastVideoPkt();
}

void AvFormatDecoderDVD::ReleaseLastVideoPkt()
void AvFormatDecoderDVD::ReleaseLastVideoPkt(void)
{
if (m_lastVideoPkt)
{
Expand All @@ -35,18 +41,18 @@ void AvFormatDecoderDVD::ReleaseLastVideoPkt()
}
}

void AvFormatDecoderDVD::ReleaseContext(MythDVDContext *&context)
void AvFormatDecoderDVD::ReleaseContext(MythDVDContext *&Context)
{
if (context)
if (Context)
{
context->DecrRef();
context = nullptr;
Context->DecrRef();
Context = nullptr;
}
}

void AvFormatDecoderDVD::Reset(bool reset_video_data, bool seek_reset, bool reset_file)
void AvFormatDecoderDVD::Reset(bool ResetVideoData, bool SeekReset, bool ResetFile)
{
AvFormatDecoder::Reset(reset_video_data, seek_reset, reset_file);
AvFormatDecoder::Reset(ResetVideoData, SeekReset, ResetFile);
SyncPositionMap();
}

Expand All @@ -56,9 +62,9 @@ void AvFormatDecoderDVD::UpdateFramesPlayed(void)
if (!m_ringBuffer->IsDVD())
return;

auto currentpos = (long long)(m_ringBuffer->DVD()->GetCurrentTime() * m_fps);
auto currentpos = static_cast<long long>(m_ringBuffer->DVD()->GetCurrentTime() * m_fps);
m_framesPlayed = m_framesRead = currentpos ;
m_parent->SetFramesPlayed(currentpos + 1);
m_parent->SetFramesPlayed(static_cast<uint64_t>(currentpos + 1));
}

bool AvFormatDecoderDVD::GetFrame(DecodeType /*Type*/, bool &Retry)
Expand All @@ -67,7 +73,7 @@ bool AvFormatDecoderDVD::GetFrame(DecodeType /*Type*/, bool &Retry)
return AvFormatDecoder::GetFrame(kDecodeAV, Retry);
}

int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt, bool& storePacket)
int AvFormatDecoderDVD::ReadPacket(AVFormatContext *Ctx, AVPacket* Pkt, bool& StorePacket)
{
int result = 0;

Expand All @@ -77,19 +83,16 @@ int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt, bool& st

if (m_lastVideoPkt)
{
av_packet_ref(pkt, m_lastVideoPkt);

av_packet_ref(Pkt, m_lastVideoPkt);
if (m_lastVideoPkt->pts != AV_NOPTS_VALUE)
m_lastVideoPkt->pts += pkt->duration;

m_lastVideoPkt->pts += Pkt->duration;
if (m_lastVideoPkt->dts != AV_NOPTS_VALUE)
m_lastVideoPkt->dts += pkt->duration;
m_lastVideoPkt->dts += Pkt->duration;
}
else
{
LOG(VB_GENERAL, LOG_ERR, LOC + QString( "Need to generate frame @ %1 - %2 but no frame available!")
.arg(pkt->pts)
.arg(m_framesReq));
.arg(Pkt->pts).arg(m_framesReq));
}
}
else
Expand All @@ -111,10 +114,8 @@ int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt, bool& st
// Non-seamless jump - clear all buffers
m_framesReq = 0;
ReleaseContext(m_curContext);

while (!m_contextList.empty())
m_contextList.takeFirst()->DecrRef();

Reset(true, false, false);
m_audio->Reset();
m_parent->DiscardVideoFrames(false, false);
Expand All @@ -133,14 +134,12 @@ int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt, bool& st
// buffer.

// Force AvFormatDecoder to stop buffering frames
storePacket = false;

StorePacket = false;
// Return the first buffered packet
AVPacket *storedPkt = m_storedPackets.takeFirst();
av_packet_ref(pkt, storedPkt);
av_packet_ref(Pkt, storedPkt);
av_packet_unref(storedPkt);
delete storedPkt;

return 0;
}
break;
Expand All @@ -150,7 +149,6 @@ int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt, bool& st
// and the ringbuffer returned to make sure that any packets still in
// ffmpeg's buffers were flushed.
break;

default:
LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unexpected DVD event - %1")
.arg(lastEvent));
Expand All @@ -160,19 +158,19 @@ int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt, bool& st
m_ringBuffer->DVD()->UnblockReading();
}

result = av_read_frame(ctx, pkt);
result = av_read_frame(Ctx, Pkt);

// Make sure we yield. Otherwise other threads may not
// get chance to take the lock. Shouldn't be necessary
// but calling up the OSD menu in a still frame without
// this still causes a deadlock.
usleep(0);
}while (m_ringBuffer->DVD()->IsReadingBlocked());
std::this_thread::yield();
} while (m_ringBuffer->DVD()->IsReadingBlocked());

if (result >= 0)
{
pkt->dts = m_ringBuffer->DVD()->AdjustTimestamp(pkt->dts);
pkt->pts = m_ringBuffer->DVD()->AdjustTimestamp(pkt->pts);
Pkt->dts = m_ringBuffer->DVD()->AdjustTimestamp(Pkt->dts);
Pkt->pts = m_ringBuffer->DVD()->AdjustTimestamp(Pkt->pts);

if (m_returnContext)
{
Expand All @@ -181,7 +179,7 @@ int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt, bool& st
// the packets through that let us find it.
gotPacket = false;

AVStream *curstream = m_ic->streams[pkt->stream_index];
AVStream *curstream = m_ic->streams[Pkt->stream_index];

if ((curstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ||
(curstream->codecpar->codec_id == AV_CODEC_ID_DVD_NAV))
Expand All @@ -191,34 +189,28 @@ int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt, bool& st
}
}
}
}while(!gotPacket);
} while(!gotPacket);
}

return result;
}

void AvFormatDecoderDVD::CheckContext(int64_t pts)
void AvFormatDecoderDVD::CheckContext(int64_t Pts)
{
if (pts != AV_NOPTS_VALUE)
if (Pts != AV_NOPTS_VALUE)
{
// Remove any contexts we should have
// already processed.(but have somehow jumped past)
while (!m_contextList.empty() &&
pts >= m_contextList.first()->GetEndPTS())
while (!m_contextList.empty() && (Pts >= m_contextList.first()->GetEndPTS()))
{
ReleaseContext(m_curContext);
m_curContext = m_contextList.takeFirst();

LOG(VB_GENERAL, LOG_ERR, LOC +
QString("DVD context missed! lba: %1, curpts: %2, nav end pts: %3")
.arg(m_curContext->GetLBA())
.arg(pts)
.arg(m_curContext->GetEndPTS()));
LOG(VB_GENERAL, LOG_ERR, LOC + QString("DVD context missed! lba: %1, curpts: %2, nav end pts: %3")
.arg(m_curContext->GetLBA()).arg(Pts).arg(m_curContext->GetEndPTS()));
}

// See whether we can take the next context from the list
if (!m_contextList.empty() &&
pts >= m_contextList.first()->GetStartPTS())
if (!m_contextList.empty() && (Pts >= m_contextList.first()->GetStartPTS()))
{
ReleaseContext(m_curContext);
m_curContext = m_contextList.takeFirst();
Expand Down Expand Up @@ -249,16 +241,13 @@ void AvFormatDecoderDVD::CheckContext(int64_t pts)
{
LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Missing video. Jumping to sector %1")
.arg(lastVideoSector));

m_ringBuffer->DVD()->SectorSeek(lastVideoSector);

m_returnContext = m_curContext;
m_curContext = nullptr;
}
else
{
LOG(VB_GENERAL, LOG_ERR, LOC +
QString("Missing video frame and no previous frame available! lba: %1")
LOG(VB_GENERAL, LOG_ERR, LOC + QString("Missing video frame and no previous frame available! lba: %1")
.arg(m_curContext->GetLBA()));
}
}
Expand All @@ -274,20 +263,20 @@ void AvFormatDecoderDVD::CheckContext(int64_t pts)
}


bool AvFormatDecoderDVD::ProcessVideoPacket(AVStream *stream, AVPacket *pkt, bool &Retry)
bool AvFormatDecoderDVD::ProcessVideoPacket(AVStream *Stream, AVPacket *Pkt, bool &Retry)
{
int64_t pts = pkt->pts;
int64_t pts = Pkt->pts;

if (pts == AV_NOPTS_VALUE)
pts = pkt->dts;
pts = Pkt->dts;

CheckContext(pts);

bool ret = AvFormatDecoder::ProcessVideoPacket(stream, pkt, Retry);
bool ret = AvFormatDecoder::ProcessVideoPacket(Stream, Pkt, Retry);
if (Retry)
return ret;

if (ret && m_curContext && (pts != AV_NOPTS_VALUE) && (pts + pkt->duration == m_curContext->GetSeqEndPTS()))
if (ret && m_curContext && (pts != AV_NOPTS_VALUE) && (pts + Pkt->duration == m_curContext->GetSeqEndPTS()))
{
// If this video frame is the last in the sequence,
// make a copy of it so we can 'generate' more
Expand All @@ -304,7 +293,7 @@ bool AvFormatDecoderDVD::ProcessVideoPacket(AVStream *stream, AVPacket *pkt, boo
}

av_init_packet(m_lastVideoPkt);
av_packet_ref(m_lastVideoPkt, pkt);
av_packet_ref(m_lastVideoPkt, Pkt);
m_lbaLastVideoPkt = m_curContext->GetLBA();

if (m_returnContext)
Expand All @@ -322,42 +311,41 @@ bool AvFormatDecoderDVD::ProcessVideoPacket(AVStream *stream, AVPacket *pkt, boo
else
{
if (m_lastVideoPkt->pts != AV_NOPTS_VALUE)
m_lastVideoPkt->pts += pkt->duration;
m_lastVideoPkt->pts += Pkt->duration;

if (m_lastVideoPkt->dts != AV_NOPTS_VALUE)
m_lastVideoPkt->dts += pkt->duration;
m_lastVideoPkt->dts += Pkt->duration;

m_framesReq = m_curContext->GetNumFrames() - m_curContext->GetNumFramesPresent();

LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "SeqEnd @ %1 - require %2 frame(s)")
.arg(pkt->pts)
.arg(m_framesReq));
.arg(Pkt->pts).arg(m_framesReq));
}
}

return ret;
}

bool AvFormatDecoderDVD::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
bool AvFormatDecoderDVD::ProcessVideoFrame(AVStream *Stream, AVFrame *Frame)
{
bool ret = true;

if (m_returnContext == nullptr)
{
// Only process video frames if we're not searching for
// the previous video frame after seeking in a slideshow.
ret = AvFormatDecoder::ProcessVideoFrame(stream, mpa_pic);
ret = AvFormatDecoder::ProcessVideoFrame(Stream, Frame);
}

return ret;
}

bool AvFormatDecoderDVD::ProcessDataPacket(AVStream *curstream, AVPacket *pkt,
DecodeType decodetype)
bool AvFormatDecoderDVD::ProcessDataPacket(AVStream *Curstream, AVPacket *Pkt,
DecodeType Decodetype)
{
bool ret = true;

if (curstream->codecpar->codec_id == AV_CODEC_ID_DVD_NAV)
if (Curstream->codecpar->codec_id == AV_CODEC_ID_DVD_NAV)
{
MythDVDContext* context = m_ringBuffer->DVD()->GetDVDContext();

Expand All @@ -381,8 +369,7 @@ bool AvFormatDecoderDVD::ProcessDataPacket(AVStream *curstream, AVPacket *pkt,
m_lastVideoPkt->dts = m_lastVideoPkt->pts;
}
}
else
if (m_lastVideoPkt)
else if (m_lastVideoPkt)
{
// If we've been generating frames, see whether this
// new context should be used already (handles
Expand All @@ -393,7 +380,7 @@ bool AvFormatDecoderDVD::ProcessDataPacket(AVStream *curstream, AVPacket *pkt,
}
else
{
ret = AvFormatDecoder::ProcessDataPacket(curstream, pkt, decodetype);
ret = AvFormatDecoder::ProcessDataPacket(Curstream, Pkt, Decodetype);
}

return ret;
Expand Down Expand Up @@ -492,10 +479,9 @@ void AvFormatDecoderDVD::PostProcessTracks(void)
}
}
}
m_tracks[kTrackTypeSubtitle] = filteredTracks;

stable_sort(m_tracks[kTrackTypeSubtitle].begin(),
m_tracks[kTrackTypeSubtitle].end());
m_tracks[kTrackTypeSubtitle] = filteredTracks;
stable_sort(m_tracks[kTrackTypeSubtitle].begin(), m_tracks[kTrackTypeSubtitle].end());

int trackNo = -1;
int selectedStream = m_ringBuffer->DVD()->GetTrack(kTrackTypeSubtitle);
Expand Down Expand Up @@ -527,8 +513,7 @@ void AvFormatDecoderDVD::PostProcessTracks(void)
uint captionmode = m_parent->GetCaptionMode();
int trackcount = static_cast<int>(m_tracks[kTrackTypeSubtitle].size());

if (captionmode == kDisplayAVSubtitle &&
(trackNo < 0 || trackNo >= trackcount))
if (captionmode == kDisplayAVSubtitle && (trackNo < 0 || trackNo >= trackcount))
{
m_parent->EnableSubtitles(false);
}
Expand All @@ -540,25 +525,25 @@ void AvFormatDecoderDVD::PostProcessTracks(void)
}
}

bool AvFormatDecoderDVD::DoRewindSeek(long long desiredFrame)
bool AvFormatDecoderDVD::DoRewindSeek(long long DesiredFrame)
{
if (!m_ringBuffer->IsDVD())
return false;

m_ringBuffer->Seek(DVDFindPosition(desiredFrame), SEEK_SET);
m_framesPlayed = m_framesRead = m_lastKey = desiredFrame + 1;
m_ringBuffer->Seek(DVDFindPosition(DesiredFrame), SEEK_SET);
m_framesPlayed = m_framesRead = m_lastKey = DesiredFrame + 1;
m_frameCounter += 100;
return true;
}

void AvFormatDecoderDVD::DoFastForwardSeek(long long desiredFrame, bool &needflush)
void AvFormatDecoderDVD::DoFastForwardSeek(long long DesiredFrame, bool &NeedFlush)
{
if (!m_ringBuffer->IsDVD())
return;

m_ringBuffer->Seek(DVDFindPosition(desiredFrame),SEEK_SET);
needflush = true;
m_framesPlayed = m_framesRead = m_lastKey = desiredFrame + 1;
m_ringBuffer->Seek(DVDFindPosition(DesiredFrame), SEEK_SET);
NeedFlush = true;
m_framesPlayed = m_framesRead = m_lastKey = DesiredFrame + 1;
m_frameCounter += 100;
}

Expand Down Expand Up @@ -603,19 +588,17 @@ void AvFormatDecoderDVD::StreamChangeCheck(void)
}
}

int AvFormatDecoderDVD::GetAudioLanguage(uint audio_index, uint stream_index)
int AvFormatDecoderDVD::GetAudioLanguage(uint /*AudioIndex*/, uint StreamIndex)
{
(void)audio_index;
if ((m_ic->streams[stream_index]->id >= 0) &&
m_ringBuffer && m_ringBuffer->IsDVD())
if ((m_ic->streams[StreamIndex]->id >= 0) && (m_ringBuffer && m_ringBuffer->IsDVD()))
{
auto track = m_ringBuffer->DVD()->GetAudioTrackNum(static_cast<uint>(m_ic->streams[stream_index]->id));
auto track = m_ringBuffer->DVD()->GetAudioTrackNum(static_cast<uint>(m_ic->streams[StreamIndex]->id));
return static_cast<int>(m_ringBuffer->DVD()->GetAudioLanguage(track));
}
return iso639_str3_to_key("und");
}

long long AvFormatDecoderDVD::DVDFindPosition(long long desiredFrame)
long long AvFormatDecoderDVD::DVDFindPosition(long long DesiredFrame)
{
if (!m_ringBuffer->IsDVD())
return 0;
Expand All @@ -625,12 +608,12 @@ long long AvFormatDecoderDVD::DVDFindPosition(long long desiredFrame)
if (m_parent)
{
ffrewSkip = m_parent->GetFFRewSkip();
current_speed = (int)m_parent->GetNextPlaySpeed();
current_speed = static_cast<int>(m_parent->GetNextPlaySpeed());
}

if (ffrewSkip == 1 || ffrewSkip == 0)
{
int diffTime = (int)ceil((desiredFrame - m_framesPlayed) / m_fps);
int diffTime = static_cast<int>(ceil((DesiredFrame - m_framesPlayed) / m_fps));
long long desiredTimePos = m_ringBuffer->DVD()->GetCurrentTime() +
diffTime;
if (diffTime <= 0)
Expand All @@ -645,14 +628,14 @@ long long AvFormatDecoderDVD::DVDFindPosition(long long desiredFrame)
return current_speed;
}

AudioTrackType AvFormatDecoderDVD::GetAudioTrackType(uint stream_index)
AudioTrackType AvFormatDecoderDVD::GetAudioTrackType(uint Index)
{
int type = 0;

if (m_ringBuffer && m_ringBuffer->DVD())
{
int logical_idx = m_ringBuffer->DVD()->GetAudioTrackNum(m_ic->streams[stream_index]->id);
type = m_ringBuffer->DVD()->GetAudioTrackType(logical_idx);
int logical_idx = m_ringBuffer->DVD()->GetAudioTrackNum(static_cast<uint>(m_ic->streams[Index]->id));
type = m_ringBuffer->DVD()->GetAudioTrackType(static_cast<uint>(logical_idx));
}

// These are the only types defined in unofficial documentation
Expand All @@ -671,5 +654,5 @@ AudioTrackType AvFormatDecoderDVD::GetAudioTrackType(uint stream_index)
}

// If the DVD metadata doesn't include the info then we might as well fall through, maybe we'll get lucky
return AvFormatDecoder::GetAudioTrackType(stream_index);
return AvFormatDecoder::GetAudioTrackType(Index);
}
60 changes: 30 additions & 30 deletions mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#ifndef AVFORMATDECODERDVD_H
#define AVFORMATDECODERDVD_H

// Qt
#include <QList>

// MythTV
#include "avformatdecoder.h"

#define INVALID_LBA 0xbfffffff
Expand All @@ -11,41 +14,38 @@ class MythDVDContext;
class AvFormatDecoderDVD : public AvFormatDecoder
{
public:
AvFormatDecoderDVD(MythPlayer *parent, const ProgramInfo &pginfo,
PlayerFlags flags)
: AvFormatDecoder(parent, pginfo, flags) {}
AvFormatDecoderDVD(MythPlayer *Parent, const ProgramInfo &PGInfo, PlayerFlags Flags);
~AvFormatDecoderDVD() override;
void Reset(bool reset_video_data, bool seek_reset, bool reset_file) override; // AvFormatDecoder
void UpdateFramesPlayed(void) override; // AvFormatDecoder
bool GetFrame(DecodeType Type, bool &Retry) override; // AvFormatDecoder

void Reset (bool ResetVideoData, bool SeekReset, bool ResetFile) override;
void UpdateFramesPlayed(void) override;
bool GetFrame (DecodeType Type, bool &Retry) override;

protected:
int ReadPacket(AVFormatContext *ctx, AVPacket *pkt, bool &storePacket) override; // AvFormatDecoder
bool ProcessVideoPacket(AVStream *stream, AVPacket *pkt, bool &Retry) override; // AvFormatDecoder
bool ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic) override; // AvFormatDecoder
bool ProcessDataPacket(AVStream *curstream, AVPacket *pkt,
DecodeType decodetype) override; // AvFormatDecoder
int ReadPacket (AVFormatContext *Ctx, AVPacket *Pkt, bool &StorePacket) override;
bool ProcessVideoPacket(AVStream *Stream, AVPacket *Pkt, bool &Retry) override;
bool ProcessVideoFrame (AVStream *Stream, AVFrame *Frame) override;
bool ProcessDataPacket (AVStream *Curstream, AVPacket *Pkt, DecodeType Decodetype) override;

private:
bool DoRewindSeek(long long desiredFrame) override; // AvFormatDecoder
void DoFastForwardSeek(long long desiredFrame, bool &needflush) override; // AvFormatDecoder
void StreamChangeCheck(void) override; // AvFormatDecoder
void PostProcessTracks(void) override; // AvFormatDecoder
int GetAudioLanguage(uint audio_index, uint stream_index) override; // AvFormatDecoder
AudioTrackType GetAudioTrackType(uint stream_index) override; // AvFormatDecoder

void CheckContext(int64_t pts);
void ReleaseLastVideoPkt();
static void ReleaseContext(MythDVDContext *&context);

long long DVDFindPosition(long long desiredFrame);

MythDVDContext* m_curContext {nullptr};
bool DoRewindSeek (long long DesiredFrame) override;
void DoFastForwardSeek (long long DesiredFrame, bool &NeedFlush) override;
void StreamChangeCheck (void) override;
void PostProcessTracks (void) override;
int GetAudioLanguage (uint AudioIndex, uint StreamIndex) override;
AudioTrackType GetAudioTrackType(uint Index) override;

void CheckContext (int64_t Pts);
void ReleaseLastVideoPkt (void);
static void ReleaseContext (MythDVDContext *&Context);
long long DVDFindPosition(long long DesiredFrame);

MythDVDContext* m_curContext { nullptr };
QList<MythDVDContext*> m_contextList;
AVPacket* m_lastVideoPkt {nullptr};
uint32_t m_lbaLastVideoPkt {INVALID_LBA};
int m_framesReq {0};
MythDVDContext* m_returnContext {nullptr};
AVPacket* m_lastVideoPkt { nullptr };
uint32_t m_lbaLastVideoPkt { INVALID_LBA};
int m_framesReq { 0 };
MythDVDContext* m_returnContext { nullptr };
};

#endif // AVFORMATDECODERDVD_H
#endif