Skip to content

Commit

Permalink
Add Video4Linux codecs (decoder) support
Browse files Browse the repository at this point in the history
- tested on a Pi3 (H264, MPEG4, MPEG2) but should get some hardware
decoding working on other SoCs
- only 'copy back' support at present. DRM PRIME support may be added
for copy free rendering - and hopefully improved performance
- the main problem  in testing is that the Pi3 VC4 drivers do not return
any interlacing flags (kernel source tree checked) - so interlacing is
not autodetected.
- there is some static initialisation to ensure the v4l2-dec decoder
isn't available where not supported - but the check may need
improvement.
- HEVC not tested (no Pi4 here) or indeed the VC6 drivers
- requires the open source Pi drivers to be enabled.
  • Loading branch information
mark-kendall committed Jul 10, 2019
1 parent d405de6 commit eba8bab
Show file tree
Hide file tree
Showing 13 changed files with 345 additions and 6 deletions.
3 changes: 2 additions & 1 deletion mythtv/configure
Expand Up @@ -2598,7 +2598,7 @@ opengl_deps_any="agl_h GL_gl_h EGL_egl_h GLES2_gl2_h darwin windows x11"
opengles_deps="GLES2_gl2_h"
opengl_video_deps="opengl"
opengl_themepainter_deps="opengl"
v4l2_deps="backend linux_videodev2_h"
v4l2_deps="linux_videodev2_h"
v4l1_deps="backend v4l2 linux_videodev_h"
xrandr_deps="x11"
asi_deps="backend"
Expand Down Expand Up @@ -7352,6 +7352,7 @@ if enabled x11 ; then
echo "VAAPI support ${vaapi-no}"
echo "NVDEC support ${nvdec-no}"
fi
echo "Video4Linux codecs ${v4l2-no}"
echo "OpenGL support ${opengl-no}"
echo "OpenGL video ${opengl_video-no}"
echo "OpenGL ThemePainter ${opengl_themepainter-no}"
Expand Down
39 changes: 38 additions & 1 deletion mythtv/libs/libmythtv/decoders/avformatdecoder.cpp
Expand Up @@ -71,6 +71,10 @@ extern "C" {
#include "mythvdpauhelper.h"
#endif

#ifdef USING_V4L2
#include "mythv4l2m2mcontext.h"
#endif

extern "C" {
#include "libavutil/avutil.h"
#include "libavutil/error.h"
Expand Down Expand Up @@ -389,6 +393,14 @@ void AvFormatDecoder::GetDecoders(render_opts &opts)
(*opts.equiv_decoders)["vtb"].append("dummy");
(*opts.equiv_decoders)["vtb-dec"].append("dummy");
#endif
#ifdef USING_V4L2
if (MythV4L2M2MContext::HaveV4L2Codecs())
{
opts.decoders->append("v4l2-dec");
(*opts.equiv_decoders)["v4l2-dec"].append("dummy");
}
#endif

PrivateDecoder::GetDecoders(opts);
}

Expand Down Expand Up @@ -1580,6 +1592,13 @@ void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc,
m_directrendering = false;
}
else
#endif
#ifdef USING_V4L2
if (codec_is_v4l2_dec(m_video_codec_id))
{
m_directrendering = false;
}
else
#endif
if (codec1 && codec1->capabilities & AV_CODEC_CAP_DR1)
{
Expand Down Expand Up @@ -2404,7 +2423,7 @@ int AvFormatDecoder::ScanStreams(bool novideo)
}

m_video_codec_id = kCodec_NONE;
int version = mpeg_version(enc->codec_id);
uint version = mpeg_version(enc->codec_id);
if (version)
m_video_codec_id = static_cast<MythCodecID>(kCodec_MPEG1 + version - 1);

Expand Down Expand Up @@ -2520,6 +2539,24 @@ int AvFormatDecoder::ScanStreams(bool novideo)
}
}
#endif // USING_NVDEC
#ifdef USING_V4L2
if (!foundgpudecoder)
{
MythCodecID v4l2mcid;
AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P;
v4l2mcid = MythV4L2M2MContext::GetSupportedCodec(enc, &codec, dec,
mpeg_version(static_cast<int>(enc->codec_id)), pix_fmt);

if (codec_is_v4l2_dec(v4l2mcid))
{
gCodecMap->freeCodecContext(m_ic->streams[selTrack]);
enc = gCodecMap->getCodecContext(m_ic->streams[selTrack], codec);
m_video_codec_id = v4l2mcid;
enc->pix_fmt = pix_fmt;
foundgpudecoder = true;
}
}
#endif // USING_V4L2
}
// default to mpeg2
if (m_video_codec_id == kCodec_NONE)
Expand Down
9 changes: 9 additions & 0 deletions mythtv/libs/libmythtv/decoders/mythcodeccontext.cpp
Expand Up @@ -43,6 +43,10 @@
#ifdef USING_MEDIACODEC
#include "mythmediacodeccontext.h"
#endif
#ifdef USING_V4L2
#include "mythv4l2m2mcontext.h"
#endif

#include "mythcodeccontext.h"

#define LOC QString("MythCodecContext: ")
Expand Down Expand Up @@ -77,6 +81,11 @@ MythCodecContext *MythCodecContext::CreateContext(DecoderBase *Parent, MythCodec
if (codec_is_mediacodec(Codec) || codec_is_mediacodec_dec(Codec))
mctx = new MythMediaCodecContext(Parent, Codec);
#endif
#ifdef USING_V4L2
if (codec_is_v4l2_dec(Codec))
mctx = new MythV4L2M2MContext(Parent, Codec);
#endif

Q_UNUSED(Codec);

if (!mctx)
Expand Down
2 changes: 2 additions & 0 deletions mythtv/libs/libmythtv/libmythtv.pro
Expand Up @@ -662,6 +662,8 @@ using_backend {
HEADERS += recorders/v4l2encsignalmonitor.h
SOURCES += recorders/v4l2encsignalmonitor.cpp

HEADERS += mythv4l2m2mcontext.h
SOURCES += mythv4l2m2mcontext.cpp
DEFINES += USING_V4L2
}

Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/mythcodecid.cpp
Expand Up @@ -367,7 +367,7 @@ AVCodecID myth2av_codecid(MythCodecID codec_id, bool &vdpau)
return AV_CODEC_ID_NONE;
}

int mpeg_version(int codec_id)
uint mpeg_version(int codec_id)
{
switch (codec_id)
{
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/mythcodecid.h
Expand Up @@ -292,7 +292,7 @@ inline AVCodecID myth2av_codecid(MythCodecID codec_id)
}

// AV codec id convenience functions
int mpeg_version(int codec_id);
uint mpeg_version(int codec_id);
#define CODEC_IS_H264(id) (mpeg_version(id) == 5)
#define CODEC_IS_MPEG(id) (mpeg_version(id) && mpeg_version(id) <= 2)
#define CODEC_IS_FFMPEG_MPEG(id) (CODEC_IS_MPEG(id))
Expand Down
6 changes: 6 additions & 0 deletions mythtv/libs/libmythtv/mythframe.h
Expand Up @@ -484,6 +484,12 @@ static inline void copyplane(uint8_t* dst, int dst_pitch,
const uint8_t* src, int src_pitch,
int width, int height)
{
if ((dst_pitch == width) && (src_pitch == width))
{
memcpy(dst, src, static_cast<size_t>(width * height));
return;
}

for (int y = 0; y < height; y++)
{
memcpy(dst, src, static_cast<size_t>(width));
Expand Down

0 comments on commit eba8bab

Please sign in to comment.