#include "libavutil/hwcontext.h"
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
+#include "libavutil/intmath.h"
#include "avcodec.h"
#include "bytestream.h"
AVPacket *pkt = ds->in_pkt;
// copy to ensure we do not change pkt
AVPacket tmp;
- int got_frame, did_split;
+ int got_frame, actual_got_frame, did_split;
int ret;
if (!pkt->data && !avci->draining) {
tmp = *pkt;
#if FF_API_MERGE_SD
FF_DISABLE_DEPRECATION_WARNINGS
- did_split = av_packet_split_side_data(&tmp);
+ did_split = avci->compat_decode_partial_size ?
+ ff_packet_split_and_drop_side_data(&tmp) :
+ av_packet_split_side_data(&tmp);
if (did_split) {
ret = extract_packet_props(avctx->internal, &tmp);
} else {
ret = avctx->codec->decode(avctx, frame, &got_frame, &tmp);
+ if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS))
+ frame->pkt_dts = pkt->dts;
if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {
- if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS))
- frame->pkt_dts = pkt->dts;
if(!avctx->has_b_frames)
frame->pkt_pos = pkt->pos;
//FIXME these should be under if(!avctx->has_b_frames)
if (!frame->height) frame->height = avctx->height;
if (frame->format == AV_PIX_FMT_NONE) frame->format = avctx->pix_fmt;
}
- } else if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
- frame->pkt_dts = pkt->dts;
}
}
emms_c();
+ actual_got_frame = got_frame;
if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {
if (frame->flags & AV_FRAME_FLAG_DISCARD)
frame->sample_rate = avctx->sample_rate;
}
- side= av_packet_get_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, &side_size);
+ side= av_packet_get_side_data(avci->last_pkt_props, AV_PKT_DATA_SKIP_SAMPLES, &side_size);
if(side && side_size>=10) {
avctx->internal->skip_samples = AV_RL32(side) * avctx->internal->skip_samples_multiplier;
discard_padding = AV_RL32(side + 4);
avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
#endif
- if (avctx->internal->draining && !got_frame)
- avci->draining_done = 1;
+ /* do not stop draining when actual_got_frame != 0 or ret < 0 */
+ /* got_frame == 0 but actual_got_frame != 0 when frame is discarded */
+ if (avctx->internal->draining && !actual_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 (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;
+ }
+ }
avci->compat_decode_consumed += ret;
return 0;
}
+static int apply_cropping(AVCodecContext *avctx, AVFrame *frame)
+{
+ /* make sure we are noisy about decoders returning invalid cropping data */
+ if (frame->crop_left >= INT_MAX - frame->crop_right ||
+ frame->crop_top >= INT_MAX - frame->crop_bottom ||
+ (frame->crop_left + frame->crop_right) >= frame->width ||
+ (frame->crop_top + frame->crop_bottom) >= frame->height) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Invalid cropping information set by a decoder: "
+ "%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER" "
+ "(frame size %dx%d). This is a bug, please report it\n",
+ frame->crop_left, frame->crop_right, frame->crop_top, frame->crop_bottom,
+ frame->width, frame->height);
+ frame->crop_left = 0;
+ frame->crop_right = 0;
+ frame->crop_top = 0;
+ frame->crop_bottom = 0;
+ return 0;
+ }
+
+ if (!avctx->apply_cropping)
+ return 0;
+
+ return av_frame_apply_cropping(frame, avctx->flags & AV_CODEC_FLAG_UNALIGNED ?
+ AV_FRAME_CROP_UNALIGNED : 0);
+}
+
int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
{
AVCodecInternal *avci = avctx->internal;
return ret;
}
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ret = apply_cropping(avctx, frame);
+ if (ret < 0) {
+ av_frame_unref(frame);
+ return ret;
+ }
+ }
+
avctx->frame_number++;
return 0;
AVPacket *avpkt)
{
int i, ret = 0;
+ AVCodecInternal *avci = avctx->internal;
if (!avpkt->data && avpkt->size) {
av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n");
AVPacket tmp = *avpkt;
#if FF_API_MERGE_SD
FF_DISABLE_DEPRECATION_WARNINGS
- int did_split = av_packet_split_side_data(&tmp);
+ int did_split = avci->compat_decode_partial_size ?
+ ff_packet_split_and_drop_side_data(&tmp) :
+ av_packet_split_side_data(&tmp);
//apply_param_change(avctx, &tmp);
if (did_split) {
return AVERROR(ENOENT);
}
- if (hwa->capabilities & HWACCEL_CODEC_CAP_EXPERIMENTAL &&
+ if (hwa->capabilities & AV_HWACCEL_CODEC_CAP_EXPERIMENTAL &&
avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
av_log(avctx, AV_LOG_WARNING, "Ignoring experimental hwaccel: %s\n",
hwa->name);
return AVERROR(ENOMEM);
}
+ avctx->hwaccel = hwa;
if (hwa->init) {
ret = hwa->init(avctx);
if (ret < 0) {
av_freep(&avctx->internal->hwaccel_priv_data);
+ avctx->hwaccel = NULL;
return ret;
}
}
- avctx->hwaccel = hwa;
-
return 0;
}
{
int ret;
- if (avctx->hw_frames_ctx)
- return av_hwframe_get_buffer(avctx->hw_frames_ctx, frame, 0);
+ if (avctx->hw_frames_ctx) {
+ ret = av_hwframe_get_buffer(avctx->hw_frames_ctx, frame, 0);
+ frame->width = avctx->coded_width;
+ frame->height = avctx->coded_height;
+ return ret;
+ }
if ((ret = update_frame_pool(avctx, frame)) < 0)
return ret;
validate_avframe_allocation(avctx, frame);
end:
- if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions) {
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
+ !(avctx->codec->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) {
frame->width = avctx->width;
frame->height = avctx->height;
}
{
avctx->internal->draining = 0;
avctx->internal->draining_done = 0;
+ avctx->internal->nb_draining_errors = 0;
av_frame_unref(avctx->internal->buffer_frame);
av_frame_unref(avctx->internal->compat_decode_frame);
av_packet_unref(avctx->internal->buffer_pkt);