2 #include <QtAndroidExtras>
3 #include <QAndroidJniEnvironment>
17 #include "libavutil/pixfmt.h"
18 #include "libavutil/hwcontext_mediacodec.h"
19 #include "libavcodec/mediacodec.h"
20 #include "libavcodec/avcodec.h"
23 #define LOC QString("MediaCodec: ")
26 #define MC_MPEG2_SIMPLE (0x0)
27 #define MC_MPEG2_MAIN (0x1)
28 #define MC_MPEG2_422 (0x2)
29 #define MC_MPEG2_SNR (0x3)
30 #define MC_MPEG2_SPATIAL (0x4)
31 #define MC_MPEG2_HIGH (0x5)
32 #define MC_MPEG4_SIMPLE (0x0001)
33 #define MC_MPEG4_SIMPLE_SCALEABLE (0x0002)
34 #define MC_MPEG4_CORE (0x0004)
35 #define MC_MPEG4_MAIN (0x0008)
36 #define MC_MPEG4_NBIT (0x0010)
37 #define MC_MPEG4_SCALEABLE_TEX (0x0020)
38 #define MC_MPEG4_SIMPLE_FACE (0x0040)
39 #define MC_MPEG4_SIMPLE_FBA (0x0080)
40 #define MC_MPEG4_BASIC_ANIMATED (0x0100)
41 #define MC_MPEG4_HYBRID (0x0200)
42 #define MC_MPEG4_ADV_REALTIME (0x0400)
43 #define MC_MPEG4_CORE_SCALEABLE (0x0800)
44 #define MC_MPEG4_ADV_CODING (0x1000)
45 #define MC_MPEG4_ADV_CORE (0x2000)
46 #define MC_MPEG4_ADV_SCALEABLE (0x4000)
47 #define MC_MPEG4_ADV_SIMPLE (0x8000)
48 #define MC_H264_BASELINE (0x00001)
49 #define MC_H264_MAIN (0x00002)
50 #define MC_H264_EXTENDED (0x00004)
51 #define MC_H264_HIGH (0x00008)
52 #define MC_H264_HIGH10 (0x00010)
53 #define MC_H264_HIGH422 (0x00020)
54 #define MC_H264_HIGH444 (0x00040)
55 #define MC_H264_CONST_BASELINE (0x10000)
56 #define MC_H264_CONST_HIGH (0x80000)
57 #define MC_HEVC_MAIN (0x0001)
58 #define MC_HEVC_MAIN10 (0x0002)
59 #define MC_HEVC_MAIN_STILL (0x0004)
60 #define MC_HEVC_MAIN10HDR10 (0x1000)
61 #define MC_HEVC_MMAIN10HDR10PLUS (0x2000)
62 #define MC_VP8_MAIN (0x0001)
63 #define MC_VP9_0 (0x0001)
64 #define MC_VP9_1 (0x0002)
65 #define MC_VP9_2 (0x0004)
66 #define MC_VP9_3 (0x0008)
67 #define MC_VP9_2HDR (0x1000)
68 #define MC_VP9_3HDR (0x2000)
69 #define MC_VP9_2HDRPLUS (0x4000)
70 #define MC_VP9_3HDRPLUS (0x8000)
182 QSize size(Context->width, Context->height);
186 if (!interop->GetSurface())
193 AVBufferRef *hwdeviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_MEDIACODEC);
194 AVHWDeviceContext *hwdevicectx =
reinterpret_cast<AVHWDeviceContext*
>(hwdeviceref->data);
196 hwdevicectx->user_opaque = interop;
197 AVMediaCodecDeviceContext *hwctx =
reinterpret_cast<AVMediaCodecDeviceContext*
>(hwdevicectx->hwctx);
198 hwctx->surface = interop->GetSurface();
199 if (av_hwdevice_ctx_init(hwdeviceref) < 0)
201 LOG(VB_GENERAL, LOG_ERR,
LOC +
"av_hwdevice_ctx_init failed");
202 av_buffer_unref(&hwdeviceref);
206 Context->hw_device_ctx = hwdeviceref;
207 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Created MediaCodec hardware device context");
217 bool decodeonly =
Decoder ==
"mediacodec-dec";
221 if (!
Decoder.startsWith(
"mediacodec"))
235 for (
auto profile : qAsConst(profiles))
237 if (
profile.first == mythprofile &&
238 profile.second.width() >= (*Context)->width &&
239 profile.second.height() >= (*Context)->height)
248 if (found && decoder)
250 QString decodername = QString((*Codec)->name) +
"_mediacodec";
251 if (decodername ==
"mpeg2video_mediacodec")
252 decodername =
"mpeg2_mediacodec";
253 AVCodec *newCodec = avcodec_find_decoder_by_name (decodername.toLocal8Bit());
257 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"HW device type '%1' supports decoding '%2' (%3)")
258 .arg(av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_MEDIACODEC)).arg((*Codec)->name).arg(profilestr));
261 (*Context)->pix_fmt = AV_PIX_FMT_MEDIACODEC;
266 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"HW device type '%1' does not support decoding '%2' (%3)")
267 .arg(av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_MEDIACODEC)).arg((*Codec)->name).arg(profilestr));
281 Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
282 DirectRendering =
false;
300 if (AvFrame->format != AV_PIX_FMT_MEDIACODEC)
309 while (*PixFmt != AV_PIX_FMT_NONE)
311 if (*PixFmt == AV_PIX_FMT_MEDIACODEC)
312 return AV_PIX_FMT_MEDIACODEC;
315 return AV_PIX_FMT_NONE;
328 Frame->m_deinterlaceInuse2x =
false;
329 Frame->m_interlaced = 0;
330 Frame->m_interlacedReverse =
false;
331 Frame->m_topFieldFirst =
false;
333 Frame->m_alreadyDeinterlaced =
true;
349 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
350 static QMutex lock(QMutex::Recursive);
352 static QRecursiveMutex lock;
354 static bool s_initialised =
false;
357 QMutexLocker locker(&lock);
360 s_initialised =
true;
362 static const QPair<QString,QPair<MythCodecContext::CodecProfile, QList<int> > > mimetypes[] =
391 QAndroidJniEnvironment env;
392 QAndroidJniObject list(
"android/media/MediaCodecList",
"(I)V", 0);
396 QAndroidJniObject qtcodecs = list.callObjectMethod(
"getCodecInfos",
"()[Landroid/media/MediaCodecInfo;");
397 if (!qtcodecs.isValid())
401 jobjectArray codecs = qtcodecs.object<jobjectArray>();
402 jsize codeccount = env->GetArrayLength(codecs);
403 for (jsize i = 0; i < codeccount; ++i)
405 QAndroidJniObject codec(env->GetObjectArrayElement(codecs, i));
406 if (!codec.isValid())
410 if (codec.callMethod<jboolean>(
"isEncoder"))
414 QString name = codec.callObjectMethod<jstring>(
"getName").
toString();
415 if (name.contains(
"OMX.google", Qt::CaseInsensitive))
419 QAndroidJniObject qttypes = codec.callObjectMethod(
"getSupportedTypes",
"()[Ljava/lang/String;");
420 jobjectArray
types = qttypes.object<jobjectArray>();
421 jsize typecount = env->GetArrayLength(
types);
422 for (jsize j = 0; j < typecount; ++j)
424 QAndroidJniObject
type(env->GetObjectArrayElement(
types, j));
429 QString typestr =
type.toString();
430 for (
auto mimetype : mimetypes)
432 if (mimetype.first != typestr)
436 QAndroidJniObject caps = codec.callObjectMethod(
"getCapabilitiesForType",
437 "(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
438 type.object<jstring>());
443 QAndroidJniObject videocaps = caps.callObjectMethod(
"getVideoCapabilities",
444 "()Landroid/media/MediaCodecInfo$VideoCapabilities;");
445 QAndroidJniObject widthrange = videocaps.callObjectMethod(
"getSupportedWidths",
446 "()Landroid/util/Range;");
447 QAndroidJniObject heightrange = videocaps.callObjectMethod(
"getSupportedHeights",
448 "()Landroid/util/Range;");
450 QAndroidJniObject widthqt = widthrange.callObjectMethod(
"getUpper",
"()Ljava/lang/Comparable;");
451 QAndroidJniObject heightqt = heightrange.callObjectMethod(
"getUpper",
"()Ljava/lang/Comparable;");
452 int width = widthqt.callMethod<jint>(
"intValue",
"()I");
453 int height = heightqt.callMethod<jint>(
"intValue",
"()I");
456 QAndroidJniObject profiles = caps.getObjectField(
"profileLevels",
457 "[Landroid/media/MediaCodecInfo$CodecProfileLevel;");
458 jobjectArray profilearr = profiles.object<jobjectArray>();
459 jsize profilecount = env->GetArrayLength(profilearr);
460 if (profilecount < 1)
462 s_profiles.append(QPair<MythCodecContext::CodecProfile,QSize>(mimetype.second.first, QSize(width, height)));
466 for (jsize k = 0; k < profilecount; ++k)
468 jobject
profile = env->GetObjectArrayElement(profilearr, k);
469 jclass objclass = env->GetObjectClass(
profile);
470 jfieldID
id = env->GetFieldID(objclass,
"profile",
"I");
471 int value =
static_cast<int>(env->GetIntField(
profile,
id));
472 QList<int>& mcprofiles = mimetype.second.second;
473 auto sameprof = [value](
auto mcprofile) {
return value == mcprofile; };
474 if (std::any_of(mcprofiles.cbegin(), mcprofiles.cend(), sameprof))
477 s_profiles.append(QPair<MythCodecContext::CodecProfile,QSize>(
p, QSize(width, height)));
480 s_profiles.append(QPair<MythCodecContext::CodecProfile,QSize>(mimetype.second.first, QSize(width, height)));
492 if (profiles.isEmpty())
495 Decoders.append(
"MediaCodec:");
496 for (
auto profile : qAsConst(profiles))
502 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
503 static QMutex lock(QMutex::Recursive);
505 static QRecursiveMutex lock;
507 static bool s_initialised =
false;
508 static bool s_available =
false;
510 QMutexLocker locker(&lock);
511 if (!s_initialised || Reinit)
514 if (profiles.isEmpty())
516 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No MediaCodec decoders found");
521 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available MediaCodec decoders:");
522 for (
auto profile : qAsConst(profiles))
524 LOG(VB_GENERAL, LOG_INFO,
LOC +
529 s_initialised =
true;