staticenum AVSampleFormat mcdec_map_pcm_format(AVCodecContext *avctx,
MediaCodecDecContext *s, int pcm_format)
{ enum AVSampleFormat ret = AV_SAMPLE_FMT_NONE;
for (int i = 0; i < FF_ARRAY_ELEMS(sample_formats); i++) { if (sample_formats[i].pcm_format == pcm_format) { return sample_formats[i].sample_format;
}
}
av_log(avctx, AV_LOG_ERROR, "Output sample format 0x%x (value=%d) is not supported\n",
pcm_format, pcm_format);
return0;
fail:
av_freep(&buffer);
status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0); if (status < 0) {
av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
ret = AVERROR_EXTERNAL;
}
return ret;
}
staticint mediacodec_wrap_sw_audio_buffer(AVCodecContext *avctx,
MediaCodecDecContext *s,
uint8_t *data,
size_t size,
ssize_t index,
FFAMediaCodecBufferInfo *info,
AVFrame *frame)
{ int ret = 0; int status = 0; constint sample_size = av_get_bytes_per_sample(avctx->sample_fmt); if (!sample_size) {
av_log(avctx, AV_LOG_ERROR, "Could not get bytes per sample\n");
ret = AVERROR(ENOSYS); goto done;
}
if (info->size % (sample_size * avctx->ch_layout.nb_channels)) {
av_log(avctx, AV_LOG_ERROR, "input is not a multiple of channels * sample_size\n");
ret = AVERROR(EINVAL); goto done;
}
ret = av_channel_layout_copy(&frame->ch_layout, &avctx->ch_layout); if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Could not copy channel layout\n"); goto done;
}
/* MediaCodec buffers needs to be copied to our own refcounted buffers *becausetheflushcommandinvalidatesallinputandoutputbuffers.
*/
ret = ff_get_buffer(avctx, frame, 0); if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer\n"); goto done;
}
/* Override frame->pts as ff_get_buffer will override its value based *onthelastavpacketreceivedwhichisnotinsyncwiththeframe: **Navpacketscanbepushedbefore1frameisactuallyreturned
* * 0-sized avpackets are pushed to flush remaining frames at EOS */ if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
frame->pts = av_rescale_q(info->presentationTimeUs,
AV_TIME_BASE_Q,
avctx->pkt_timebase);
} else {
frame->pts = info->presentationTimeUs;
}
frame->pkt_dts = AV_NOPTS_VALUE;
frame->flags |= AV_FRAME_FLAG_KEY;
ret = 0;
done:
status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0); if (status < 0) {
av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
ret = AVERROR_EXTERNAL;
}
return ret;
}
staticint mediacodec_wrap_sw_video_buffer(AVCodecContext *avctx,
MediaCodecDecContext *s,
uint8_t *data,
size_t size,
ssize_t index,
FFAMediaCodecBufferInfo *info,
AVFrame *frame)
{ int ret = 0; int status = 0;
/* MediaCodec buffers needs to be copied to our own refcounted buffers *becausetheflushcommandinvalidatesallinputandoutputbuffers.
*/ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer\n"); goto done;
}
/* Override frame->pkt_pts as ff_get_buffer will override its value based *onthelastavpacketreceivedwhichisnotinsyncwiththeframe: **Navpacketscanbepushedbefore1frameisactuallyreturned
* * 0-sized avpackets are pushed to flush remaining frames at EOS */ if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
frame->pts = av_rescale_q(info->presentationTimeUs,
AV_TIME_BASE_Q,
avctx->pkt_timebase);
} else {
frame->pts = info->presentationTimeUs;
}
frame->pkt_dts = AV_NOPTS_VALUE;
switch (s->color_format) { case COLOR_FormatYUV420Planar:
ff_mediacodec_sw_buffer_copy_yuv420_planar(avctx, s, data, size, info, frame); break; case COLOR_FormatYUV420SemiPlanar: case COLOR_QCOM_FormatYUV420SemiPlanar: case COLOR_QCOM_FormatYUV420SemiPlanar32m:
ff_mediacodec_sw_buffer_copy_yuv420_semi_planar(avctx, s, data, size, info, frame); break; case COLOR_TI_FormatYUV420PackedSemiPlanar: case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:
ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar(avctx, s, data, size, info, frame); break; case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:
ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka(avctx, s, data, size, info, frame); break; default:
av_log(avctx, AV_LOG_ERROR, "Unsupported color format 0x%x (value=%d)\n",
s->color_format, s->color_format);
ret = AVERROR(EINVAL); goto done;
}
ret = 0;
done:
status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0); if (status < 0) {
av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
ret = AVERROR_EXTERNAL;
}
#define AMEDIAFORMAT_GET_INT32(name, key, mandatory) do { \
int32_t value = 0; \ if (ff_AMediaFormat_getInt32(s->format, key, &value)) { \
(name) = value; \
} elseif (mandatory) { \
av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", key, format); \
ret = AVERROR_EXTERNAL; \ goto fail; \
} else { \
(name) = 0; \
} \
} while (0) \
staticint mediacodec_dec_parse_video_format(AVCodecContext *avctx, MediaCodecDecContext *s)
{ int ret = 0; int width = 0; int height = 0; int color_range = 0; int color_standard = 0; int color_transfer = 0; char *format = NULL;
if (!s->format) {
av_log(avctx, AV_LOG_ERROR, "Output MediaFormat is not set\n"); return AVERROR(EINVAL);
}
format = ff_AMediaFormat_toString(s->format); if (!format) { return AVERROR_EXTERNAL;
}
av_log(avctx, AV_LOG_DEBUG, "Parsing MediaFormat %s\n", format);
AMEDIAFORMAT_GET_INT32(s->color_format, "color-format", 1);
avctx->pix_fmt = mcdec_map_color_format(avctx, s, s->color_format); if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
av_log(avctx, AV_LOG_ERROR, "Output color format is not supported\n");
ret = AVERROR(EINVAL); goto fail;
}
staticint mediacodec_dec_parse_audio_format(AVCodecContext *avctx, MediaCodecDecContext *s)
{ int ret = 0; int sample_rate = 0; int channel_count = 0; int channel_mask = 0; int pcm_encoding = 0; char *format = NULL;
if (!s->format) {
av_log(avctx, AV_LOG_ERROR, "Output MediaFormat is not set\n"); return AVERROR(EINVAL);
}
format = ff_AMediaFormat_toString(s->format); if (!format) { return AVERROR_EXTERNAL;
}
av_log(avctx, AV_LOG_DEBUG, "Parsing MediaFormat %s\n", format);
profile = ff_AMediaCodecProfile_getProfileFromAVCodecContext(avctx); if (profile < 0) {
av_log(avctx, AV_LOG_WARNING, "Unsupported or unknown profile\n");
}
s->codec_name = ff_AMediaCodecList_getCodecNameByType(mime, profile, 0, avctx); if (!s->codec_name) { // getCodecNameByType() can fail due to missing JVM, while NDK // mediacodec can be used without JVM. if (!s->use_ndk_codec) { return AVERROR_EXTERNAL;
}
av_log(avctx, AV_LOG_INFO, "Failed to getCodecNameByType\n");
} else {
av_log(avctx, AV_LOG_DEBUG, "Found decoder %s\n", s->codec_name);
}
if (s->codec_name)
s->codec = ff_AMediaCodec_createCodecByName(s->codec_name, s->use_ndk_codec); else {
s->codec = ff_AMediaCodec_createDecoderByType(mime, s->use_ndk_codec); if (s->codec) {
s->codec_name = ff_AMediaCodec_getName(s->codec); if (!s->codec_name)
s->codec_name = av_strdup(mime);
}
} if (!s->codec) {
av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for type %s and name %s\n", mime, s->codec_name); return AVERROR_EXTERNAL;
}
return0;
}
staticint mediacodec_dec_get_audio_codec(AVCodecContext *avctx, MediaCodecDecContext *s, constchar *mime, FFAMediaFormat *format)
{
s->codec = ff_AMediaCodec_createDecoderByType(mime, s->use_ndk_codec); if (!s->codec) {
av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for mime %s\n", mime); return AVERROR_EXTERNAL;
}
s->codec_name = ff_AMediaCodec_getName(s->codec); if (!s->codec_name) {
s->codec_name = av_strdup(mime); if (!s->codec_name) return AVERROR(ENOMEM);
}
return0;
}
int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, constchar *mime, FFAMediaFormat *format)
{ int ret; int status;
int ff_mediacodec_dec_send(AVCodecContext *avctx, MediaCodecDecContext *s,
AVPacket *pkt, bool wait)
{ int offset = 0; int need_draining = 0;
uint8_t *data;
size_t size;
FFAMediaCodec *codec = s->codec; int status;
int64_t input_dequeue_timeout_us = wait ? INPUT_DEQUEUE_TIMEOUT_US : 0;
int64_t pts;
if (s->flushing) {
av_log(avctx, AV_LOG_ERROR, "Decoder is flushing and cannot accept new buffer " "until all output buffers have been released\n"); return AVERROR_EXTERNAL;
}
if (pkt->size == 0) {
need_draining = 1;
}
if (s->draining && s->eos) { return AVERROR_EOF;
}
while (offset < pkt->size || (need_draining && !s->draining)) {
ssize_t index = s->current_input_buffer; if (index < 0) {
index = ff_AMediaCodec_dequeueInputBuffer(codec, input_dequeue_timeout_us); if (ff_AMediaCodec_infoTryAgainLater(codec, index)) {
av_log(avctx, AV_LOG_TRACE, "No input buffer available, try again later\n"); break;
}
data = ff_AMediaCodec_getInputBuffer(codec, index, &size); if (!data) {
av_log(avctx, AV_LOG_ERROR, "Failed to get input buffer\n"); return AVERROR_EXTERNAL;
}
if (offset == 0) return AVERROR(EAGAIN); return offset;
}
int ff_mediacodec_dec_receive(AVCodecContext *avctx, MediaCodecDecContext *s,
AVFrame *frame, bool wait)
{ int ret;
uint8_t *data;
ssize_t index;
size_t size;
FFAMediaCodec *codec = s->codec;
FFAMediaCodecBufferInfo info = { 0 }; int status;
int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US;
if (s->draining && s->eos) { return AVERROR_EOF;
}
if (s->draining) { /* If the codec is flushing or need to be flushed, block for a fair
* amount of time to ensure we got a frame */
output_dequeue_timeout_us = OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US;
} elseif (s->output_buffer_count == 0 || !wait) { /* If the codec hasn't produced any frames, do not block so we *canpushdatatoitasfastaspossible,andgetthefirst
* frame */
output_dequeue_timeout_us = 0;
}
} elseif (ff_AMediaCodec_infoOutputBuffersChanged(codec, index)) {
ff_AMediaCodec_cleanOutputBuffers(codec);
} elseif (ff_AMediaCodec_infoTryAgainLater(codec, index)) { if (s->draining) {
av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer within %" PRIi64 "ms " "while draining remaining frames, output will probably lack frames\n",
output_dequeue_timeout_us / 1000);
} else {
av_log(avctx, AV_LOG_TRACE, "No output buffer available, try again later\n");
}
} else {
av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer (status=%zd)\n", index); return AVERROR_EXTERNAL;
}
if (s->draining && s->eos) return AVERROR_EOF; return AVERROR(EAGAIN);
}
/* *ff_mediacodec_dec_flushreturns0iftheflushcannotbeperformedon *thecodec(becausetheuserretainsframes).Thecodecstaysinthe *flushingstate. * *ff_mediacodec_dec_flushreturns1iftheflushcanactuallybe *performedonthecodec.Thecodecleavestheflushingstateandcan *processagainpackets. * *ff_mediacodec_dec_flushreturnsanegativevalueifanerrorhas *occurred.
*/ int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s)
{ if (!s->surface || !s->delay_flush || atomic_load(&s->refcount) == 1) { int ret;
/* No frames (holding a reference to the codec) are retained by the
* user, thus we can flush the codec and returns accordingly */ if ((ret = mediacodec_dec_flush_codec(avctx, s)) < 0) { return ret;
}
return1;
}
s->flushing = 1; return0;
}
int ff_mediacodec_dec_close(AVCodecContext *avctx, MediaCodecDecContext *s)
{ if (!s) return0;
if (s->codec) { if (atomic_load(&s->hw_buffer_count) == 0) {
ff_AMediaCodec_stop(s->codec);
av_log(avctx, AV_LOG_DEBUG, "MediaCodec %p stopped\n", s->codec);
} else {
av_log(avctx, AV_LOG_DEBUG, "Not stopping MediaCodec (there are buffers pending)\n");
}
}
ff_mediacodec_dec_unref(s);
return0;
}
int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx, MediaCodecDecContext *s)
{ return s->flushing;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.39 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.