3#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4#include <QtAndroidExtras>
5#include <QAndroidJniEnvironment>
8#include <QCoreApplication>
9#include <QJniEnvironment>
11#define QAndroidJniEnvironment QJniEnvironment
12#define QAndroidJniObject QJniObject
27#include "libavutil/pixfmt.h"
28#include "libavutil/hwcontext_mediacodec.h"
29#include "libavcodec/mediacodec.h"
30#include "libavcodec/avcodec.h"
33#define LOC QString("MediaCodec: ")
206 QSize size(Context->width, Context->height);
210 if (!interop->GetSurface())
217 AVBufferRef *hwdeviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_MEDIACODEC);
218 auto *hwdevicectx =
reinterpret_cast<AVHWDeviceContext*
>(hwdeviceref->data);
220 hwdevicectx->user_opaque = interop;
221 auto *hwctx =
reinterpret_cast<AVMediaCodecDeviceContext*
>(hwdevicectx->hwctx);
222 hwctx->surface = interop->GetSurface();
223 if (av_hwdevice_ctx_init(hwdeviceref) < 0)
225 LOG(VB_GENERAL, LOG_ERR,
LOC +
"av_hwdevice_ctx_init failed");
226 av_buffer_unref(&hwdeviceref);
230 Context->hw_device_ctx = hwdeviceref;
231 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Created MediaCodec hardware device context");
236 const AVCodec **Codec,
241 bool decodeonly =
Decoder ==
"mediacodec-dec";
245 if (!
Decoder.startsWith(
"mediacodec"))
259 for (
auto profile : std::as_const(profiles))
261 if (
profile.first == mythprofile &&
262 profile.second.width() >= (*Context)->width &&
263 profile.second.height() >= (*Context)->height)
272 if (found && decoder)
274 QString decodername = QString((*Codec)->name) +
"_mediacodec";
275 if (decodername ==
"mpeg2video_mediacodec")
276 decodername =
"mpeg2_mediacodec";
277 const AVCodec *newCodec = avcodec_find_decoder_by_name (decodername.toLocal8Bit().constData());
281 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"HW device type '%1' supports decoding '%2' (%3)")
282 .arg(av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_MEDIACODEC)).arg((*Codec)->name).arg(profilestr));
283 decoder->CodecMap()->FreeCodecContext(Stream);
284 *Context = decoder->CodecMap()->GetCodecContext(Stream, *Codec);
285 (*Context)->pix_fmt = AV_PIX_FMT_MEDIACODEC;
290 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"HW device type '%1' does not support decoding '%2' (%3)")
291 .arg(av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_MEDIACODEC)).arg((*Codec)->name).arg(profilestr));
305 Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
306 DirectRendering =
false;
324 if (AvFrame->format != AV_PIX_FMT_MEDIACODEC)
333 while (*PixFmt != AV_PIX_FMT_NONE)
335 if (*PixFmt == AV_PIX_FMT_MEDIACODEC)
336 return AV_PIX_FMT_MEDIACODEC;
339 return AV_PIX_FMT_NONE;
352 Frame->m_deinterlaceInuse2x =
false;
353 Frame->m_interlaced =
false;
354 Frame->m_interlacedReverse =
false;
355 Frame->m_topFieldFirst =
false;
357 Frame->m_alreadyDeinterlaced =
true;
373 static QRecursiveMutex lock;
374 static bool s_initialised =
false;
377 QMutexLocker locker(&lock);
380 s_initialised =
true;
382 static const std::vector< QPair<QString,QPair<MythCodecContext::CodecProfile, QList<int> > > > mimetypes =
416 QAndroidJniObject qtcodecs = list.callObjectMethod(
"getCodecInfos",
"()[Landroid/media/MediaCodecInfo;");
417 if (!qtcodecs.isValid())
421 auto *codecs = qtcodecs.object<jobjectArray>();
422 jsize codeccount = env->GetArrayLength(codecs);
423 for (jsize i = 0; i < codeccount; ++i)
426 if (!codec.isValid())
430 if (codec.callMethod<jboolean>(
"isEncoder"))
434 QString name = codec.callObjectMethod<jstring>(
"getName").
toString();
435 if (name.contains(
"OMX.google", Qt::CaseInsensitive))
439 QAndroidJniObject qttypes = codec.callObjectMethod(
"getSupportedTypes",
"()[Ljava/lang/String;");
440 auto *
types = qttypes.object<jobjectArray>();
441 jsize typecount = env->GetArrayLength(
types);
442 for (jsize j = 0; j < typecount; ++j)
449 QString typestr =
type.toString();
450 for (
const auto& mimetype : mimetypes)
452 if (mimetype.first != typestr)
457 "(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
458 type.object<jstring>());
464 "()Landroid/media/MediaCodecInfo$VideoCapabilities;");
466 "()Landroid/util/Range;");
467 QAndroidJniObject heightrange = videocaps.callObjectMethod(
"getSupportedHeights",
468 "()Landroid/util/Range;");
470 QAndroidJniObject widthqt = widthrange.callObjectMethod(
"getUpper",
"()Ljava/lang/Comparable;");
471 QAndroidJniObject heightqt = heightrange.callObjectMethod(
"getUpper",
"()Ljava/lang/Comparable;");
472 int width = widthqt.callMethod<jint>(
"intValue",
"()I");
473 int height = heightqt.callMethod<jint>(
"intValue",
"()I");
477 "[Landroid/media/MediaCodecInfo$CodecProfileLevel;");
478 auto *profilearr = profiles.object<jobjectArray>();
479 jsize profilecount = env->GetArrayLength(profilearr);
480 if (profilecount < 1)
482 s_profiles.append(QPair<MythCodecContext::CodecProfile,QSize>(mimetype.second.first, QSize(width, height)));
486 for (jsize k = 0; k < profilecount; ++k)
488 jobject
profile = env->GetObjectArrayElement(profilearr, k);
489 jclass objclass = env->GetObjectClass(
profile);
490 jfieldID
id = env->GetFieldID(objclass,
"profile",
"I");
491 int value =
static_cast<int>(env->GetIntField(
profile,
id));
492 const QList<int>& mcprofiles = mimetype.second.second;
493 auto sameprof = [value](
auto mcprofile) {
return value == mcprofile; };
494 if (std::ranges::any_of(mcprofiles, sameprof))
497 s_profiles.append(QPair<MythCodecContext::CodecProfile,QSize>(
p, QSize(width, height)));
501 s_profiles.append(QPair<MythCodecContext::CodecProfile,QSize>(mimetype.second.first, QSize(width, height)));
514 if (profiles.isEmpty())
517 Decoders.append(
"MediaCodec:");
518 for (
auto profile : std::as_const(profiles))
524 static QRecursiveMutex lock;
525 static bool s_initialised =
false;
526 static bool s_available =
false;
528 QMutexLocker locker(&lock);
529 if (!s_initialised || Reinit)
532 if (profiles.isEmpty())
534 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No MediaCodec decoders found");
539 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available MediaCodec decoders:");
540 for (
auto profile : std::as_const(profiles))
542 LOG(VB_GENERAL, LOG_INFO,
LOC +
547 s_initialised =
true;
static void DeviceContextFinished(AVHWDeviceContext *Context)
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
@ MPEG4AdvancedScaleableTexture
@ H264ConstrainedBaseline
static int InitialiseDecoder2(AVCodecContext *Context, CreateHWDecoder Callback, const QString &Debug)
Initialise a hardware decoder that is NOT expected to use AVHWFramesContext.
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
static bool GetBuffer2(struct AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int Flags)
A generic hardware buffer initialisation method when AVHWFramesContext is NOT used.
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
static CodecProfile FFmpegToMythProfile(AVCodecID CodecID, int Profile)
int HwDecoderInit(AVCodecContext *Context) override
static MythCodecID GetBestSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
void PostProcessFrame(AVCodecContext *, MythVideoFrame *Frame) override
Mark all MediaCodec decoded frames as progressive,.
MythMediaCodecContext(DecoderBase *Parent, MythCodecID CodecID)
static bool HaveMediaCodec(bool Reinit=false)
bool IsDeinterlacing(bool &DoubleRate, bool=false) override
static AVPixelFormat GetFormat(AVCodecContext *, const AVPixelFormat *PixFmt)
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
static void GetDecoderList(QStringList &Decoders)
static int InitialiseDecoder(AVCodecContext *Context)
static MCProfiles & GetProfiles(void)
static const struct wl_interface * types[]
static bool codec_is_mediacodec_dec(MythCodecID id)
@ kCodec_MPEG1_MEDIACODEC_DEC
@ kCodec_MPEG1_MEDIACODEC
static bool codec_is_mediacodec(MythCodecID id)
static bool CODEC_IS_MEDIACODEC(const struct AVCodec *)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
#define QAndroidJniEnvironment
MythCodecContext::CodecProfile MediaCodecToMythProfile(int Codec, int Profile)
@ MC_MPEG4_BASIC_ANIMATED
@ MC_MPEG4_SIMPLE_SCALEABLE
@ MC_MPEG4_CORE_SCALEABLE
@ MC_HEVC_MMAIN10HDR10PLUS
#define QAndroidJniObject
QList< QPair< MythCodecContext::CodecProfile, QSize > > MCProfiles
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.