2317 lines · 72.9 KB · C
RawDownload
/* * generic decoding-related code * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <stdint.h>#include <stdbool.h>#include <string.h> #include "config.h" #if CONFIG_ICONV# include <iconv.h>#endif #include "libavutil/avassert.h"#include "libavutil/channel_layout.h"#include "libavutil/common.h"#include "libavutil/emms.h"#include "libavutil/frame.h"#include "libavutil/hwcontext.h"#include "libavutil/imgutils.h"#include "libavutil/internal.h"#include "libavutil/mastering_display_metadata.h"#include "libavutil/mem.h"#include "libavutil/stereo3d.h" #include "avcodec.h"#include "avcodec_internal.h"#include "bytestream.h"#include "bsf.h"#include "codec_desc.h"#include "codec_internal.h"#include "decode.h"#include "hwaccel_internal.h"#include "hwconfig.h"#include "internal.h"#include "lcevcdec.h"#include "packet_internal.h"#include "progressframe.h"#include "libavutil/refstruct.h"#include "thread.h"#include "threadprogress.h" typedef struct DecodeContext {    AVCodecInternal avci;     /**     * This is set to AV_FRAME_FLAG_KEY for decoders of intra-only formats     * (those whose codec descriptor has AV_CODEC_PROP_INTRA_ONLY set)     * to set the flag generically.     */    int intra_only_flag;     /**     * This is set to AV_PICTURE_TYPE_I for intra only video decoders     * and to AV_PICTURE_TYPE_NONE for other decoders. It is used to set     * the AVFrame's pict_type before the decoder receives it.     */    enum AVPictureType initial_pict_type;     /* to prevent infinite loop on errors when draining */    int nb_draining_errors;     /**     * The caller has submitted a NULL packet on input.     */    int draining_started;     int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far    int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far    int64_t pts_correction_last_pts;       /// PTS of the last frame    int64_t pts_correction_last_dts;       /// DTS of the last frame     /**     * Bitmask indicating for which side data types we prefer user-supplied     * (global or attached to packets) side data over bytestream.     */    uint64_t side_data_pref_mask;     FFLCEVCContext *lcevc;    int lcevc_frame;    int width;    int height;} DecodeContext; static DecodeContext *decode_ctx(AVCodecInternal *avci){    return (DecodeContext *)avci;} static int apply_param_change(AVCodecContext *avctx, const AVPacket *avpkt){    int ret;    size_t size;    const uint8_t *data;    uint32_t flags;    int64_t val;     data = av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, &size);    if (!data)        return 0;     if (!(avctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE)) {        av_log(avctx, AV_LOG_ERROR, "This decoder does not support parameter "               "changes, but PARAM_CHANGE side data was sent to it.\n");        ret = AVERROR(EINVAL);        goto fail2;    }     if (size < 4)        goto fail;     flags = bytestream_get_le32(&data);    size -= 4;     if (flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) {        if (size < 4)            goto fail;        val = bytestream_get_le32(&data);        if (val <= 0 || val > INT_MAX) {            av_log(avctx, AV_LOG_ERROR, "Invalid sample rate");            ret = AVERROR_INVALIDDATA;            goto fail2;        }        avctx->sample_rate = val;        size -= 4;    }    if (flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) {        if (size < 8)            goto fail;        avctx->width  = bytestream_get_le32(&data);        avctx->height = bytestream_get_le32(&data);        size -= 8;        ret = ff_set_dimensions(avctx, avctx->width, avctx->height);        if (ret < 0)            goto fail2;    }     return 0;fail:    av_log(avctx, AV_LOG_ERROR, "PARAM_CHANGE side data too small.\n");    ret = AVERROR_INVALIDDATA;fail2:    if (ret < 0) {        av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");        if (avctx->err_recognition & AV_EF_EXPLODE)            return ret;    }    return 0;} static int extract_packet_props(AVCodecInternal *avci, const AVPacket *pkt){    int ret = 0;     av_packet_unref(avci->last_pkt_props);    if (pkt) {        ret = av_packet_copy_props(avci->last_pkt_props, pkt);#if FF_API_FRAME_PKT        if (!ret)            avci->last_pkt_props->stream_index = pkt->size; // Needed for ff_decode_frame_props().#endif    }    return ret;} static int decode_bsfs_init(AVCodecContext *avctx){    AVCodecInternal *avci = avctx->internal;    const FFCodec *const codec = ffcodec(avctx->codec);    int ret;     if (avci->bsf)        return 0;     ret = av_bsf_list_parse_str(codec->bsfs, &avci->bsf);    if (ret < 0) {        av_log(avctx, AV_LOG_ERROR, "Error parsing decoder bitstream filters '%s': %s\n", codec->bsfs, av_err2str(ret));        if (ret != AVERROR(ENOMEM))            ret = AVERROR_BUG;        goto fail;    }     /* We do not currently have an API for passing the input timebase into decoders,     * but no filters used here should actually need it.     * So we make up some plausible-looking number (the MPEG 90kHz timebase) */    avci->bsf->time_base_in = (AVRational){ 1, 90000 };    ret = avcodec_parameters_from_context(avci->bsf->par_in, avctx);    if (ret < 0)        goto fail;     ret = av_bsf_init(avci->bsf);    if (ret < 0)        goto fail;     return 0;fail:    av_bsf_free(&avci->bsf);    return ret;} #if !HAVE_THREADS#define ff_thread_get_packet(avctx, pkt) (AVERROR_BUG)#define ff_thread_receive_frame(avctx, frame) (AVERROR_BUG)#endif static int decode_get_packet(AVCodecContext *avctx, AVPacket *pkt){    AVCodecInternal *avci = avctx->internal;    int ret;     ret = av_bsf_receive_packet(avci->bsf, pkt);    if (ret < 0)        return ret;     if (!(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) {        ret = extract_packet_props(avctx->internal, pkt);        if (ret < 0)            goto finish;    }     ret = apply_param_change(avctx, pkt);    if (ret < 0)        goto finish;     return 0;finish:    av_packet_unref(pkt);    return ret;} int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt){    AVCodecInternal *avci = avctx->internal;    DecodeContext     *dc = decode_ctx(avci);     if (avci->draining)        return AVERROR_EOF;     /* If we are a worker thread, get the next packet from the threading     * context. Otherwise we are the main (user-facing) context, so we get the     * next packet from the input filterchain.     */    if (avctx->internal->is_frame_mt)        return ff_thread_get_packet(avctx, pkt);     while (1) {        int ret = decode_get_packet(avctx, pkt);        if (ret == AVERROR(EAGAIN) &&            (!AVPACKET_IS_EMPTY(avci->buffer_pkt) || dc->draining_started)) {            ret = av_bsf_send_packet(avci->bsf, avci->buffer_pkt);            if (ret >= 0)                continue;             av_packet_unref(avci->buffer_pkt);        }         if (ret == AVERROR_EOF)            avci->draining = 1;        return ret;    }} /** * Attempt to guess proper monotonic timestamps for decoded video frames * which might have incorrect times. Input timestamps may wrap around, in * which case the output will as well. * * @param pts the pts field of the decoded AVPacket, as passed through * AVFrame.pts * @param dts the dts field of the decoded AVPacket * @return one of the input values, may be AV_NOPTS_VALUE */static int64_t guess_correct_pts(DecodeContext *dc,                                 int64_t reordered_pts, int64_t dts){    int64_t pts = AV_NOPTS_VALUE;     if (dts != AV_NOPTS_VALUE) {        dc->pts_correction_num_faulty_dts += dts <= dc->pts_correction_last_dts;        dc->pts_correction_last_dts = dts;    } else if (reordered_pts != AV_NOPTS_VALUE)        dc->pts_correction_last_dts = reordered_pts;     if (reordered_pts != AV_NOPTS_VALUE) {        dc->pts_correction_num_faulty_pts += reordered_pts <= dc->pts_correction_last_pts;        dc->pts_correction_last_pts = reordered_pts;    } else if(dts != AV_NOPTS_VALUE)        dc->pts_correction_last_pts = dts;     if ((dc->pts_correction_num_faulty_pts<=dc->pts_correction_num_faulty_dts || dts == AV_NOPTS_VALUE)       && reordered_pts != AV_NOPTS_VALUE)        pts = reordered_pts;    else        pts = dts;     return pts;} static int discard_samples(AVCodecContext *avctx, AVFrame *frame, int64_t *discarded_samples){    AVCodecInternal *avci = avctx->internal;    AVFrameSideData *side;    uint32_t discard_padding = 0;    uint8_t skip_reason = 0;    uint8_t discard_reason = 0;     side = av_frame_get_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES);    if (side && side->size >= 10) {        avci->skip_samples = AV_RL32(side->data);        avci->skip_samples = FFMAX(0, avci->skip_samples);        discard_padding = AV_RL32(side->data + 4);        av_log(avctx, AV_LOG_DEBUG, "skip %d / discard %d samples due to side data\n",               avci->skip_samples, (int)discard_padding);        skip_reason = AV_RL8(side->data + 8);        discard_reason = AV_RL8(side->data + 9);    }     if ((avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) {        if (!side && (avci->skip_samples || discard_padding))            side = av_frame_new_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES, 10);        if (side && (avci->skip_samples || discard_padding)) {            AV_WL32(side->data, avci->skip_samples);            AV_WL32(side->data + 4, discard_padding);            AV_WL8(side->data + 8, skip_reason);            AV_WL8(side->data + 9, discard_reason);            avci->skip_samples = 0;        }        return 0;    }    av_frame_remove_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES);     if ((frame->flags & AV_FRAME_FLAG_DISCARD)) {        avci->skip_samples = FFMAX(0, avci->skip_samples - frame->nb_samples);        *discarded_samples += frame->nb_samples;        return AVERROR(EAGAIN);    }     if (avci->skip_samples > 0) {        if (frame->nb_samples <= avci->skip_samples){            *discarded_samples += frame->nb_samples;            avci->skip_samples -= frame->nb_samples;            av_log(avctx, AV_LOG_DEBUG, "skip whole frame, skip left: %d\n",                   avci->skip_samples);            return AVERROR(EAGAIN);        } else {            av_samples_copy(frame->extended_data, frame->extended_data, 0, avci->skip_samples,                            frame->nb_samples - avci->skip_samples, avctx->ch_layout.nb_channels, frame->format);            if (avctx->pkt_timebase.num && avctx->sample_rate) {                int64_t diff_ts = av_rescale_q(avci->skip_samples,                                               (AVRational){1, avctx->sample_rate},                                               avctx->pkt_timebase);                if (frame->pts != AV_NOPTS_VALUE)                    frame->pts += diff_ts;                if (frame->pkt_dts != AV_NOPTS_VALUE)                    frame->pkt_dts += diff_ts;                if (frame->duration >= diff_ts)                    frame->duration -= diff_ts;            } else                av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for skipped samples.\n");             av_log(avctx, AV_LOG_DEBUG, "skip %d/%d samples\n",                   avci->skip_samples, frame->nb_samples);            *discarded_samples += avci->skip_samples;            frame->nb_samples -= avci->skip_samples;            avci->skip_samples = 0;        }    }     if (discard_padding > 0 && discard_padding <= frame->nb_samples) {        if (discard_padding == frame->nb_samples) {            *discarded_samples += frame->nb_samples;            return AVERROR(EAGAIN);        } else {            if (avctx->pkt_timebase.num && avctx->sample_rate) {                int64_t diff_ts = av_rescale_q(frame->nb_samples - discard_padding,                                               (AVRational){1, avctx->sample_rate},                                               avctx->pkt_timebase);                frame->duration = diff_ts;            } else                av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for discarded samples.\n");             av_log(avctx, AV_LOG_DEBUG, "discard %d/%d samples\n",                   (int)discard_padding, frame->nb_samples);            frame->nb_samples -= discard_padding;        }    }     return 0;} /* * The core of the receive_frame_wrapper for the decoders implementing * the simple API. Certain decoders might consume partial packets without * returning any output, so this function needs to be called in a loop until it * returns EAGAIN. **/static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame, int64_t *discarded_samples){    AVCodecInternal   *avci = avctx->internal;    DecodeContext     *dc = decode_ctx(avci);    AVPacket     *const pkt = avci->in_pkt;    const FFCodec *const codec = ffcodec(avctx->codec);    int got_frame, consumed;    int ret;     if (!pkt->data && !avci->draining) {        av_packet_unref(pkt);        ret = ff_decode_get_packet(avctx, pkt);        if (ret < 0 && ret != AVERROR_EOF)            return ret;    }     // Some codecs (at least wma lossless) will crash when feeding drain packets    // after EOF was signaled.    if (avci->draining_done)        return AVERROR_EOF;     if (!pkt->data &&        !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))        return AVERROR_EOF;     got_frame = 0;     frame->pict_type = dc->initial_pict_type;    frame->flags    |= dc->intra_only_flag;    consumed = codec->cb.decode(avctx, frame, &got_frame, pkt);     if (!(codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS))        frame->pkt_dts = pkt->dts;    if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {#if FF_API_FRAME_PKTFF_DISABLE_DEPRECATION_WARNINGS        if(!avctx->has_b_frames)            frame->pkt_pos = pkt->pos;FF_ENABLE_DEPRECATION_WARNINGS#endif    }    emms_c();     if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {        ret = (!got_frame || frame->flags & AV_FRAME_FLAG_DISCARD)                          ? AVERROR(EAGAIN)                          : 0;    } else if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {        ret =  !got_frame ? AVERROR(EAGAIN)                          : discard_samples(avctx, frame, discarded_samples);    } else        av_assert0(0);     if (ret == AVERROR(EAGAIN))        av_frame_unref(frame);     // FF_CODEC_CB_TYPE_DECODE decoders must not return AVERROR EAGAIN    // code later will add AVERROR(EAGAIN) to a pointer    av_assert0(consumed != AVERROR(EAGAIN));    if (consumed < 0)        ret = consumed;    if (consumed >= 0 && avctx->codec->type == AVMEDIA_TYPE_VIDEO)        consumed = pkt->size;     if (!ret)        av_assert0(frame->buf[0]);    if (ret == AVERROR(EAGAIN))        ret = 0;     /* do not stop draining when got_frame != 0 or ret < 0 */    if (avci->draining && !got_frame) {        if (ret < 0) {            /* prevent infinite loop if a decoder wrongly always return error on draining */            /* reasonable nb_errors_max = maximum b frames + thread count */            int nb_errors_max = 20 + (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME ?                                avctx->thread_count : 1);             if (decode_ctx(avci)->nb_draining_errors++ >= nb_errors_max) {                av_log(avctx, AV_LOG_ERROR, "Too many errors when draining, this is a bug. "                       "Stop draining and force EOF.\n");                avci->draining_done = 1;                ret = AVERROR_BUG;            }        } else {            avci->draining_done = 1;        }    }

Lines 1–500 of 2317.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t