1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-11-26 19:01:44 +02:00
FFmpeg/libavcodec/h263dec.c

745 lines
25 KiB
C
Raw Normal View History

/*
* H.263 decoder
* Copyright (c) 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
* 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
*/
/**
* @file
* H.263 decoder.
*/
#define UNCHECKED_BITSTREAM_READER 1
#include "config_components.h"
#include "avcodec.h"
#include "codec_internal.h"
#include "decode.h"
#include "error_resilience.h"
#include "flvdec.h"
#include "h263.h"
#include "h263dec.h"
#include "hwaccel_internal.h"
#include "hwconfig.h"
#include "mpeg_er.h"
#include "mpeg4video.h"
#include "mpeg4videodec.h"
#include "mpeg4videodefs.h"
#include "mpegvideo.h"
#include "mpegvideodec.h"
#include "msmpeg4dec.h"
#include "thread.h"
#include "wmv2dec.h"
static const enum AVPixelFormat h263_hwaccel_pixfmt_list_420[] = {
#if CONFIG_H263_VAAPI_HWACCEL || CONFIG_MPEG4_VAAPI_HWACCEL
AV_PIX_FMT_VAAPI,
#endif
#if CONFIG_MPEG4_NVDEC_HWACCEL
AV_PIX_FMT_CUDA,
#endif
#if CONFIG_MPEG4_VDPAU_HWACCEL
AV_PIX_FMT_VDPAU,
#endif
#if CONFIG_H263_VIDEOTOOLBOX_HWACCEL || CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL
AV_PIX_FMT_VIDEOTOOLBOX,
#endif
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
};
static enum AVPixelFormat h263_get_format(AVCodecContext *avctx)
{
/* MPEG-4 Studio Profile only, not supported by hardware */
if (avctx->bits_per_raw_sample > 8) {
av_assert1(((MpegEncContext *)avctx->priv_data)->studio_profile);
return avctx->pix_fmt;
}
if (CONFIG_GRAY && (avctx->flags & AV_CODEC_FLAG_GRAY)) {
if (avctx->color_range == AVCOL_RANGE_UNSPECIFIED)
avctx->color_range = AVCOL_RANGE_MPEG;
return AV_PIX_FMT_GRAY8;
}
if (avctx->codec_id == AV_CODEC_ID_H263 ||
avctx->codec_id == AV_CODEC_ID_H263P ||
avctx->codec_id == AV_CODEC_ID_MPEG4)
return avctx->pix_fmt = ff_get_format(avctx, h263_hwaccel_pixfmt_list_420);
return AV_PIX_FMT_YUV420P;
}
av_cold int ff_h263_decode_init(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
int ret;
s->out_format = FMT_H263;
// set defaults
avcodec/mpegpicture: Make MPVPicture refcounted Up until now, an initialized MpegEncContext had an array of MPVPictures (way more than were ever needed) and the MPVPicture* contained in the MPVWorkPictures as well as the input_picture and reordered_input_picture arrays (for the encoder) pointed into this array. Several of the pointers could point to the same slot and because there was no reference counting involved, one had to check for aliasing before unreferencing. Furthermore, given that these pointers were not ownership pointers the pointers were often simply reset without unreferencing the slot (happened e.g. for the RV30 and RV40 decoders) or there were moved without resetting the src pointer (happened for the encoders where the entries in the input_picture and reordered_input_picture arrays were not reset). Instead actually releasing these pictures was performed by looping over the whole array and checking which one of the entries needed to be kept. Given that the array had way too many slots (36), this meant that more than 30 MPVPictures have been unnecessarily unreferenced in every ff_mpv_frame_start(); something similar happened for the encoder. This commit changes this by making the MPVPictures refcounted via the RefStruct API. The MPVPictures itself are part of a pool so that this does not entail constant allocations; instead, the amount of allocations actually goes down, because the earlier code used such a large array of MPVPictures (36 entries) and allocated an AVFrame for every one of these on every ff_mpv_common_init(). In fact, the pool is only freed when closing the codec, so that reinitializations don't lead to new allocations (this avoids having to sync the pool in update_thread_context). Making MPVPictures refcounted also has another key benefit: It makes it possible to directly share them across threads (when using frame-threaded decoding), eliminating ugly code with underlying av_frame_ref()'s; sharing these pictures can't fail any more. The pool is allocated in ff_mpv_decode_init() for decoders, which therefore can fail now. This and the fact that the pool is not unreferenced in ff_mpv_common_end() also necessitated to mark several mpegvideo-decoders with the FF_CODEC_CAP_INIT_CLEANUP flag. *: This also means that there is no good reason any more for ff_mpv_common_frame_size_change() to exist. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-15 21:34:43 +02:00
ret = ff_mpv_decode_init(s, avctx);
if (ret < 0)
return ret;
s->decode_mb = ff_h263_decode_mb;
s->low_delay = 1;
// dct_unquantize defaults for H.263;
// they might change on a per-frame basis for MPEG-4.
s->dct_unquantize_intra = s->dct_unquantize_h263_intra;
s->dct_unquantize_inter = s->dct_unquantize_h263_inter;
/* select sub codec */
switch (avctx->codec->id) {
case AV_CODEC_ID_H263:
Merge commit '36ef5369ee9b336febc2c270f8718cec4476cb85' * commit '36ef5369ee9b336febc2c270f8718cec4476cb85': Replace all CODEC_ID_* with AV_CODEC_ID_* lavc: add AV prefix to codec ids. Conflicts: doc/APIchanges doc/examples/decoding_encoding.c doc/examples/muxing.c ffmpeg.c ffprobe.c ffserver.c libavcodec/8svx.c libavcodec/avcodec.h libavcodec/dnxhd_parser.c libavcodec/dvdsubdec.c libavcodec/error_resilience.c libavcodec/h263dec.c libavcodec/libvorbisenc.c libavcodec/mjpeg_parser.c libavcodec/mjpegenc.c libavcodec/mpeg12.c libavcodec/mpeg4videodec.c libavcodec/mpegvideo.c libavcodec/mpegvideo_enc.c libavcodec/pcm.c libavcodec/r210dec.c libavcodec/utils.c libavcodec/v210dec.c libavcodec/version.h libavdevice/alsa-audio-dec.c libavdevice/bktr.c libavdevice/v4l2.c libavformat/asfdec.c libavformat/asfenc.c libavformat/avformat.h libavformat/avidec.c libavformat/caf.c libavformat/electronicarts.c libavformat/flacdec.c libavformat/flvdec.c libavformat/flvenc.c libavformat/framecrcenc.c libavformat/img2.c libavformat/img2dec.c libavformat/img2enc.c libavformat/ipmovie.c libavformat/isom.c libavformat/matroska.c libavformat/matroskadec.c libavformat/matroskaenc.c libavformat/mov.c libavformat/movenc.c libavformat/mp3dec.c libavformat/mpeg.c libavformat/mpegts.c libavformat/mxf.c libavformat/mxfdec.c libavformat/mxfenc.c libavformat/nsvdec.c libavformat/nut.c libavformat/oggenc.c libavformat/pmpdec.c libavformat/rawdec.c libavformat/rawenc.c libavformat/riff.c libavformat/sdp.c libavformat/utils.c libavformat/vocenc.c libavformat/wtv.c libavformat/xmv.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
2012-08-07 23:45:46 +03:00
case AV_CODEC_ID_H263P:
avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
break;
case AV_CODEC_ID_MPEG4:
// dct_unquantize_inter is only used with MPEG-2 quantizers,
// so we can already set dct_unquantize_inter here once and for all.
s->dct_unquantize_inter = s->dct_unquantize_mpeg2_inter;
break;
case AV_CODEC_ID_MSMPEG4V1:
s->h263_pred = 1;
s->msmpeg4_version = MSMP4_V1;
break;
case AV_CODEC_ID_MSMPEG4V2:
s->h263_pred = 1;
s->msmpeg4_version = MSMP4_V2;
break;
case AV_CODEC_ID_MSMPEG4V3:
s->h263_pred = 1;
s->msmpeg4_version = MSMP4_V3;
break;
case AV_CODEC_ID_WMV1:
s->h263_pred = 1;
s->msmpeg4_version = MSMP4_WMV1;
break;
case AV_CODEC_ID_WMV2:
s->h263_pred = 1;
s->msmpeg4_version = MSMP4_WMV2;
break;
case AV_CODEC_ID_H263I:
case AV_CODEC_ID_RV10:
case AV_CODEC_ID_RV20:
break;
case AV_CODEC_ID_FLV1:
s->h263_flv = 1;
break;
default:
2013-10-26 20:31:46 +03:00
av_log(avctx, AV_LOG_ERROR, "Unsupported codec %d\n",
avctx->codec->id);
return AVERROR(ENOSYS);
}
if (avctx->codec_tag == AV_RL32("L263") || avctx->codec_tag == AV_RL32("S263"))
if (avctx->extradata_size == 56 && avctx->extradata[0] == 1)
s->ehc_mode = 1;
/* for H.263, we allocate the images after having read the header */
if (avctx->codec->id != AV_CODEC_ID_H263 &&
avctx->codec->id != AV_CODEC_ID_H263P &&
avctx->codec->id != AV_CODEC_ID_MPEG4) {
avctx->pix_fmt = h263_get_format(avctx);
if ((ret = ff_mpv_common_init(s)) < 0)
return ret;
}
ff_h263dsp_init(&s->h263dsp);
ff_h263_decode_init_vlc();
return 0;
}
/**
* Return the number of bytes consumed for building the current frame.
*/
static int get_consumed_bytes(MpegEncContext *s, int buf_size)
{
int pos = (get_bits_count(&s->gb) + 7) >> 3;
if (s->divx_packed || s->avctx->hwaccel) {
/* We would have to scan through the whole buf to handle the weird
* reordering ... */
return buf_size;
} else {
// avoid infinite loops (maybe not needed...)
if (pos == 0)
pos = 1;
// oops ;)
if (pos + 10 > buf_size)
pos = buf_size;
return pos;
}
}
static int decode_slice(MpegEncContext *s)
{
const int part_mask = s->partitioned_frame
? (ER_AC_END | ER_AC_ERROR) : 0x7F;
const int mb_size = 16 >> s->avctx->lowres;
int ret;
s->last_resync_gb = s->gb;
s->first_slice_line = 1;
s->resync_mb_x = s->mb_x;
s->resync_mb_y = s->mb_y;
ff_set_qscale(s, s->qscale);
if (s->studio_profile) {
if ((ret = ff_mpeg4_decode_studio_slice_header(s->avctx->priv_data)) < 0)
return ret;
}
if (s->avctx->hwaccel) {
const uint8_t *start = s->gb.buffer + get_bits_count(&s->gb) / 8;
ret = FF_HW_CALL(s->avctx, decode_slice, start, s->gb.buffer_end - start);
// ensure we exit decode loop
s->mb_y = s->mb_height;
return ret;
}
if (s->partitioned_frame) {
const int qscale = s->qscale;
if (CONFIG_MPEG4_DECODER && s->codec_id == AV_CODEC_ID_MPEG4)
if ((ret = ff_mpeg4_decode_partitions(s->avctx->priv_data)) < 0)
return ret;
/* restore variables which were modified */
s->first_slice_line = 1;
s->mb_x = s->resync_mb_x;
s->mb_y = s->resync_mb_y;
ff_set_qscale(s, qscale);
}
for (; s->mb_y < s->mb_height; s->mb_y++) {
/* per-row end of slice checks */
if (s->msmpeg4_version != MSMP4_UNUSED) {
if (s->resync_mb_y + s->slice_height == s->mb_y) {
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y,
s->mb_x - 1, s->mb_y, ER_MB_END);
return 0;
}
}
if (s->msmpeg4_version == MSMP4_V1) {
s->last_dc[0] =
s->last_dc[1] =
s->last_dc[2] = 128;
}
ff_init_block_index(s);
for (; s->mb_x < s->mb_width; s->mb_x++) {
int ret;
ff_update_block_index(s, s->avctx->bits_per_raw_sample,
s->avctx->lowres, s->chroma_x_shift);
if (s->resync_mb_x == s->mb_x && s->resync_mb_y + 1 == s->mb_y)
s->first_slice_line = 0;
/* DCT & quantize */
s->mv_dir = MV_DIR_FORWARD;
s->mv_type = MV_TYPE_16X16;
ff_dlog(s, "%d %06X\n",
get_bits_count(&s->gb), show_bits(&s->gb, 24));
ff_tlog(NULL, "Decoding MB at %dx%d\n", s->mb_x, s->mb_y);
ret = s->decode_mb(s, s->block);
if (s->pict_type != AV_PICTURE_TYPE_B)
ff_h263_update_motion_val(s);
if (ret < 0) {
const int xy = s->mb_x + s->mb_y * s->mb_stride;
if (ret == SLICE_END) {
ff_mpv_reconstruct_mb(s, s->block);
if (s->loop_filter)
ff_h263_loop_filter(s);
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y,
s->mb_x, s->mb_y, ER_MB_END & part_mask);
s->padding_bug_score--;
if (++s->mb_x >= s->mb_width) {
s->mb_x = 0;
ff_mpeg_draw_horiz_band(s, s->mb_y * mb_size, mb_size);
ff_mpv_report_decode_progress(s);
s->mb_y++;
}
return 0;
} else if (ret == SLICE_NOEND) {
av_log(s->avctx, AV_LOG_ERROR,
"Slice mismatch at MB: %d\n", xy);
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y,
s->mb_x + 1, s->mb_y,
ER_MB_END & part_mask);
return AVERROR_INVALIDDATA;
}
av_log(s->avctx, AV_LOG_ERROR, "Error at MB: %d\n", xy);
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y,
s->mb_x, s->mb_y, ER_MB_ERROR & part_mask);
if ((s->avctx->err_recognition & AV_EF_IGNORE_ERR) && get_bits_left(&s->gb) > 0)
continue;
return AVERROR_INVALIDDATA;
}
ff_mpv_reconstruct_mb(s, s->block);
if (s->loop_filter)
ff_h263_loop_filter(s);
}
ff_mpeg_draw_horiz_band(s, s->mb_y * mb_size, mb_size);
ff_mpv_report_decode_progress(s);
s->mb_x = 0;
}
av_assert1(s->mb_x == 0 && s->mb_y == s->mb_height);
// Detect incorrect padding with wrong stuffing codes used by NEC N-02B
if (s->codec_id == AV_CODEC_ID_MPEG4 &&
(s->workaround_bugs & FF_BUG_AUTODETECT) &&
get_bits_left(&s->gb) >= 48 &&
show_bits(&s->gb, 24) == 0x4010 &&
!s->data_partitioning)
s->padding_bug_score += 32;
/* try to detect the padding bug */
if (s->codec_id == AV_CODEC_ID_MPEG4 &&
(s->workaround_bugs & FF_BUG_AUTODETECT) &&
get_bits_left(&s->gb) >= 0 &&
get_bits_left(&s->gb) < 137 &&
!s->data_partitioning) {
const int bits_count = get_bits_count(&s->gb);
const int bits_left = s->gb.size_in_bits - bits_count;
if (bits_left == 0) {
s->padding_bug_score += 16;
} else if (bits_left != 1) {
int v = show_bits(&s->gb, 8);
v |= 0x7F >> (7 - (bits_count & 7));
if (v == 0x7F && bits_left <= 8)
s->padding_bug_score--;
else if (v == 0x7F && ((get_bits_count(&s->gb) + 8) & 8) &&
bits_left <= 16)
s->padding_bug_score += 4;
else
s->padding_bug_score++;
}
}
if (s->codec_id == AV_CODEC_ID_H263 &&
(s->workaround_bugs & FF_BUG_AUTODETECT) &&
get_bits_left(&s->gb) >= 8 &&
get_bits_left(&s->gb) < 300 &&
s->pict_type == AV_PICTURE_TYPE_I &&
show_bits(&s->gb, 8) == 0 &&
!s->data_partitioning) {
s->padding_bug_score += 32;
}
if (s->codec_id == AV_CODEC_ID_H263 &&
(s->workaround_bugs & FF_BUG_AUTODETECT) &&
get_bits_left(&s->gb) >= 64 &&
AV_RB64(s->gb.buffer_end - 8) == 0xCDCDCDCDFC7F0000) {
s->padding_bug_score += 32;
}
if (s->workaround_bugs & FF_BUG_AUTODETECT) {
if (
(s->padding_bug_score > -2 && !s->data_partitioning))
s->workaround_bugs |= FF_BUG_NO_PADDING;
else
s->workaround_bugs &= ~FF_BUG_NO_PADDING;
}
// handle formats which don't have unique end markers
if (s->msmpeg4_version != MSMP4_UNUSED || (s->workaround_bugs & FF_BUG_NO_PADDING)) { // FIXME perhaps solve this more cleanly
int left = get_bits_left(&s->gb);
int max_extra = 7;
/* no markers in M$ crap */
if (s->msmpeg4_version != MSMP4_UNUSED && s->pict_type == AV_PICTURE_TYPE_I)
max_extra += 17;
/* buggy padding but the frame should still end approximately at
* the bitstream end */
if ((s->workaround_bugs & FF_BUG_NO_PADDING) &&
(s->avctx->err_recognition & (AV_EF_BUFFER|AV_EF_AGGRESSIVE)))
max_extra += 48;
else if ((s->workaround_bugs & FF_BUG_NO_PADDING))
max_extra += 256 * 256 * 256 * 64;
if (left > max_extra)
av_log(s->avctx, AV_LOG_ERROR,
"discarding %d junk bits at end, next would be %X\n",
left, show_bits(&s->gb, 24));
else if (left < 0)
av_log(s->avctx, AV_LOG_ERROR, "overreading %d bits\n", -left);
else
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y,
s->mb_x - 1, s->mb_y, ER_MB_END);
return 0;
}
av_log(s->avctx, AV_LOG_ERROR,
"slice end not reached but screenspace end (%d left %06X, score= %d)\n",
get_bits_left(&s->gb), show_bits(&s->gb, 24), s->padding_bug_score);
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y,
ER_MB_END & part_mask);
return AVERROR_INVALIDDATA;
}
int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict,
int *got_frame, AVPacket *avpkt)
{
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
MpegEncContext *s = avctx->priv_data;
int ret;
int slice_ret = 0;
/* no supplementary picture */
if (buf_size == 0) {
/* special case for last picture */
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
if (s->low_delay == 0 && s->next_pic.ptr) {
if ((ret = av_frame_ref(pict, s->next_pic.ptr->f)) < 0)
return ret;
avcodec/mpegpicture: Make MPVPicture refcounted Up until now, an initialized MpegEncContext had an array of MPVPictures (way more than were ever needed) and the MPVPicture* contained in the MPVWorkPictures as well as the input_picture and reordered_input_picture arrays (for the encoder) pointed into this array. Several of the pointers could point to the same slot and because there was no reference counting involved, one had to check for aliasing before unreferencing. Furthermore, given that these pointers were not ownership pointers the pointers were often simply reset without unreferencing the slot (happened e.g. for the RV30 and RV40 decoders) or there were moved without resetting the src pointer (happened for the encoders where the entries in the input_picture and reordered_input_picture arrays were not reset). Instead actually releasing these pictures was performed by looping over the whole array and checking which one of the entries needed to be kept. Given that the array had way too many slots (36), this meant that more than 30 MPVPictures have been unnecessarily unreferenced in every ff_mpv_frame_start(); something similar happened for the encoder. This commit changes this by making the MPVPictures refcounted via the RefStruct API. The MPVPictures itself are part of a pool so that this does not entail constant allocations; instead, the amount of allocations actually goes down, because the earlier code used such a large array of MPVPictures (36 entries) and allocated an AVFrame for every one of these on every ff_mpv_common_init(). In fact, the pool is only freed when closing the codec, so that reinitializations don't lead to new allocations (this avoids having to sync the pool in update_thread_context). Making MPVPictures refcounted also has another key benefit: It makes it possible to directly share them across threads (when using frame-threaded decoding), eliminating ugly code with underlying av_frame_ref()'s; sharing these pictures can't fail any more. The pool is allocated in ff_mpv_decode_init() for decoders, which therefore can fail now. This and the fact that the pool is not unreferenced in ff_mpv_common_end() also necessitated to mark several mpegvideo-decoders with the FF_CODEC_CAP_INIT_CLEANUP flag. *: This also means that there is no good reason any more for ff_mpv_common_frame_size_change() to exist. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-15 21:34:43 +02:00
ff_mpv_unref_picture(&s->next_pic);
*got_frame = 1;
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
} else if (s->skipped_last_frame && s->cur_pic.ptr) {
/* Output the last picture we decoded again if the stream ended with
* an NVOP */
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0)
return ret;
/* Copy props from the last input packet. Otherwise, props from the last
* returned picture would be reused */
if ((ret = ff_decode_frame_props(avctx, pict)) < 0)
return ret;
avcodec/mpegpicture: Make MPVPicture refcounted Up until now, an initialized MpegEncContext had an array of MPVPictures (way more than were ever needed) and the MPVPicture* contained in the MPVWorkPictures as well as the input_picture and reordered_input_picture arrays (for the encoder) pointed into this array. Several of the pointers could point to the same slot and because there was no reference counting involved, one had to check for aliasing before unreferencing. Furthermore, given that these pointers were not ownership pointers the pointers were often simply reset without unreferencing the slot (happened e.g. for the RV30 and RV40 decoders) or there were moved without resetting the src pointer (happened for the encoders where the entries in the input_picture and reordered_input_picture arrays were not reset). Instead actually releasing these pictures was performed by looping over the whole array and checking which one of the entries needed to be kept. Given that the array had way too many slots (36), this meant that more than 30 MPVPictures have been unnecessarily unreferenced in every ff_mpv_frame_start(); something similar happened for the encoder. This commit changes this by making the MPVPictures refcounted via the RefStruct API. The MPVPictures itself are part of a pool so that this does not entail constant allocations; instead, the amount of allocations actually goes down, because the earlier code used such a large array of MPVPictures (36 entries) and allocated an AVFrame for every one of these on every ff_mpv_common_init(). In fact, the pool is only freed when closing the codec, so that reinitializations don't lead to new allocations (this avoids having to sync the pool in update_thread_context). Making MPVPictures refcounted also has another key benefit: It makes it possible to directly share them across threads (when using frame-threaded decoding), eliminating ugly code with underlying av_frame_ref()'s; sharing these pictures can't fail any more. The pool is allocated in ff_mpv_decode_init() for decoders, which therefore can fail now. This and the fact that the pool is not unreferenced in ff_mpv_common_end() also necessitated to mark several mpegvideo-decoders with the FF_CODEC_CAP_INIT_CLEANUP flag. *: This also means that there is no good reason any more for ff_mpv_common_frame_size_change() to exist. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-15 21:34:43 +02:00
ff_mpv_unref_picture(&s->cur_pic);
*got_frame = 1;
}
return 0;
}
retry:
if (s->divx_packed && s->bitstream_buffer_size) {
int i;
for(i=0; i < buf_size-3; i++) {
if (buf[i]==0 && buf[i+1]==0 && buf[i+2]==1) {
if (buf[i+3]==0xB0) {
av_log(s->avctx, AV_LOG_WARNING, "Discarding excessive bitstream in packed xvid\n");
s->bitstream_buffer_size = 0;
}
break;
}
}
}
if (s->bitstream_buffer_size && (s->divx_packed || buf_size <= MAX_NVOP_SIZE)) // divx 5.01+/xvid frame reorder
ret = init_get_bits8(&s->gb, s->bitstream_buffer,
s->bitstream_buffer_size);
else
ret = init_get_bits8(&s->gb, buf, buf_size);
s->bitstream_buffer_size = 0;
if (ret < 0)
return ret;
/* let's go :-) */
if (CONFIG_WMV2_DECODER && s->msmpeg4_version == MSMP4_WMV2) {
ret = ff_wmv2_decode_picture_header(s);
#if CONFIG_MSMPEG4DEC
} else if (s->msmpeg4_version != MSMP4_UNUSED) {
ret = ff_msmpeg4_decode_picture_header(s);
#endif
} else if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) {
ret = ff_mpeg4_decode_picture_header(avctx->priv_data, &s->gb, 0, 0);
s->skipped_last_frame = (ret == FRAME_SKIPPED);
} else if (CONFIG_H263I_DECODER && s->codec_id == AV_CODEC_ID_H263I) {
ret = ff_intel_h263_decode_picture_header(s);
} else if (CONFIG_FLV_DECODER && s->h263_flv) {
ret = ff_flv_decode_picture_header(s);
} else {
ret = ff_h263_decode_picture_header(s);
}
if (ret < 0 || ret == FRAME_SKIPPED) {
if ( s->width != avctx->coded_width
|| s->height != avctx->coded_height) {
av_log(s->avctx, AV_LOG_WARNING, "Reverting picture dimensions change due to header decoding failure\n");
s->width = avctx->coded_width;
s->height= avctx->coded_height;
}
}
if (ret == FRAME_SKIPPED)
return get_consumed_bytes(s, buf_size);
/* skip if the header was thrashed */
if (ret < 0) {
av_log(s->avctx, AV_LOG_ERROR, "header damaged\n");
return ret;
}
if (!s->context_initialized) {
avctx->pix_fmt = h263_get_format(avctx);
if ((ret = ff_mpv_common_init(s)) < 0)
return ret;
}
avctx->has_b_frames = !s->low_delay;
if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) {
if (s->pict_type != AV_PICTURE_TYPE_B && s->mb_num/2 > get_bits_left(&s->gb))
return AVERROR_INVALIDDATA;
if (ff_mpeg4_workaround_bugs(avctx) == 1)
goto retry;
if (s->studio_profile != (s->idsp.idct == NULL))
ff_mpv_idct_init(s);
if (s->mpeg_quant) {
s->dct_unquantize_intra = s->dct_unquantize_mpeg2_intra;
} else {
s->dct_unquantize_intra = s->dct_unquantize_h263_intra;
}
}
/* After H.263 & MPEG-4 header decode we have the height, width,
* and other parameters. So then we could init the picture.
* FIXME: By the way H.263 decoder is evolving it should have
* an H263EncContext */
if (s->width != avctx->coded_width ||
s->height != avctx->coded_height ||
s->context_reinit) {
/* H.263 could change picture size any time */
s->context_reinit = 0;
ret = ff_set_dimensions(avctx, s->width, s->height);
if (ret < 0)
return ret;
ff_set_sar(avctx, avctx->sample_aspect_ratio);
if ((ret = ff_mpv_common_frame_size_change(s)))
return ret;
if (avctx->pix_fmt != h263_get_format(avctx)) {
av_log(avctx, AV_LOG_ERROR, "format change not supported\n");
avctx->pix_fmt = AV_PIX_FMT_NONE;
return AVERROR_UNKNOWN;
}
}
if (s->codec_id == AV_CODEC_ID_H263 ||
s->codec_id == AV_CODEC_ID_H263P ||
s->codec_id == AV_CODEC_ID_H263I)
2015-04-28 11:38:29 +02:00
s->gob_index = H263_GOB_HEIGHT(s->height);
/* skip B-frames if we don't have reference frames */
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
if (!s->last_pic.ptr &&
(s->pict_type == AV_PICTURE_TYPE_B || s->droppable))
return get_consumed_bytes(s, buf_size);
if ((avctx->skip_frame >= AVDISCARD_NONREF &&
s->pict_type == AV_PICTURE_TYPE_B) ||
(avctx->skip_frame >= AVDISCARD_NONKEY &&
s->pict_type != AV_PICTURE_TYPE_I) ||
avctx->skip_frame >= AVDISCARD_ALL)
return get_consumed_bytes(s, buf_size);
if ((ret = ff_mpv_frame_start(s, avctx)) < 0)
return ret;
avcodec/h263dec: fix hwaccel decoding Recently we encountered an issue when decoding a h.263 file: FFmpeg will freeze when decoding h.263 video with NVDEC. Turns out this is not directly related to NVDEC but is a problem that shows with several other HW decoders like VDPAU, though the exact kind of error is different (either error messages or freezing[1]). The root cause is that ff_thread_finish_setup() is called twice per frame from ff_h263_decode_frame(). This is not supported by ff_thread_finish_setup() and specifically checked for and warned against in the functions code. The issue is also specific to hw accelerated decoding only as the second call to ff_thread_finish_setup() is only issued when hw acceleration is on. The fix is simple: add a check that the first call is only send when hw acceleration is off, and the second call only when hw acceleration is on (see attached patch). This works fine as far as I was able to test with vdpau and nvdec/nvcuvid hw decoding. The patch also adds NVDEC to the hw config list if available. I also noticed a secondary issue when browsing through the code which is that, according to documentation, ff_thread_finish_setup() should only be called if the codec implements update_thread_context(), which h263dec does not. The patch does not address this and I'm not sure any action needs to be taken here at all. [1] This is depending on whether or not the hw decoder sets the HWACCEL_CAPS_ASYNC_SAFE flag Signed-off-by: Timo Rothenpieler <timo@rothenpieler.org>
2019-08-02 11:18:10 +02:00
if (!s->divx_packed && !avctx->hwaccel)
ff_thread_finish_setup(avctx);
2013-10-26 20:31:46 +03:00
if (avctx->hwaccel) {
ret = FF_HW_CALL(avctx, start_frame,
s->gb.buffer, s->gb.buffer_end - s->gb.buffer);
2013-10-26 20:31:46 +03:00
if (ret < 0 )
return ret;
2013-10-26 20:31:46 +03:00
}
ff_mpeg_er_frame_start(s);
/* the second part of the wmv2 header contains the MB skip bits which
* are stored in current_picture->mb_type which is not available before
* ff_mpv_frame_start() */
#if CONFIG_WMV2_DECODER
if (s->msmpeg4_version == MSMP4_WMV2) {
ret = ff_wmv2_decode_secondary_picture_header(s);
if (ret < 0)
return ret;
if (ret == 1)
goto frame_end;
}
#endif
/* decode each macroblock */
s->mb_x = 0;
s->mb_y = 0;
slice_ret = decode_slice(s);
while (s->mb_y < s->mb_height) {
if (s->msmpeg4_version != MSMP4_UNUSED) {
if (s->slice_height == 0 || s->mb_x != 0 || slice_ret < 0 ||
(s->mb_y % s->slice_height) != 0 || get_bits_left(&s->gb) < 0)
break;
} else {
int prev_x = s->mb_x, prev_y = s->mb_y;
if (ff_h263_resync(s) < 0)
break;
if (prev_y * s->mb_width + prev_x < s->mb_y * s->mb_width + s->mb_x)
s->er.error_occurred = 1;
}
if (s->msmpeg4_version < MSMP4_WMV1 && s->h263_pred)
ff_mpeg4_clean_buffers(s);
if (decode_slice(s) < 0)
slice_ret = AVERROR_INVALIDDATA;
}
if (s->msmpeg4_version != MSMP4_UNUSED && s->msmpeg4_version < MSMP4_WMV1 &&
s->pict_type == AV_PICTURE_TYPE_I)
if (!CONFIG_MSMPEG4DEC ||
ff_msmpeg4_decode_ext_header(s, buf_size) < 0)
s->er.error_status_table[s->mb_num - 1] = ER_MB_ERROR;
av_assert1(s->bitstream_buffer_size == 0);
frame_end:
if (!s->studio_profile)
ff_er_frame_end(&s->er, NULL);
if (avctx->hwaccel) {
ret = FF_HW_SIMPLE_CALL(avctx, end_frame);
if (ret < 0)
return ret;
}
ff_mpv_frame_end(s);
if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4)
ff_mpeg4_frame_end(avctx, buf, buf_size);
if (!s->divx_packed && avctx->hwaccel)
ff_thread_finish_setup(avctx);
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
av_assert1(s->pict_type == s->cur_pic.ptr->f->pict_type);
if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0)
return ret;
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
ff_print_debug_info(s, s->cur_pic.ptr, pict);
ff_mpv_export_qp_table(s, pict, s->cur_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1);
} else if (s->last_pic.ptr) {
if ((ret = av_frame_ref(pict, s->last_pic.ptr->f)) < 0)
return ret;
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
ff_print_debug_info(s, s->last_pic.ptr, pict);
ff_mpv_export_qp_table(s, pict, s->last_pic.ptr, FF_MPV_QSCALE_TYPE_MPEG1);
}
avcodec/mpegpicture: Split MPVPicture into WorkPicture and ordinary Pic There are two types of MPVPictures: Three (cur_pic, last_pic, next_pic) that are directly part of MpegEncContext and an array of MPVPictures that are separately allocated and are mostly accessed via pointers (cur|last|next)_pic_ptr; they are also used to store AVFrames in the encoder (necessary due to B-frames). As the name implies, each of the former is directly associated with one of the _ptr pointers: They actually share the same underlying buffers, but the ones that are part of the context can have their data pointers offset and their linesize doubled for field pictures. Up until now, each of these had their own references; in particular, there was an underlying av_frame_ref() to sync cur_pic and cur_pic_ptr etc. This is wasteful. This commit changes this relationship: cur_pic, last_pic and next_pic now become MPVWorkPictures; this structure does not have an AVFrame at all any more, but only the cached values of data and linesize. It also contains a pointer to the corresponding MPVPicture, establishing a more natural relationsship between the two. This already means that creating the context-pictures from the pointers can no longer fail. What has not been changed is the fact that the MPVPicture* pointers are not ownership pointers and that the MPVPictures are part of an array of MPVPictures that is owned by a single AVCodecContext. Doing so will be done in a latter commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-08 12:25:07 +02:00
if (s->last_pic.ptr || s->low_delay) {
if ( pict->format == AV_PIX_FMT_YUV420P
&& (s->codec_tag == AV_RL32("GEOV") || s->codec_tag == AV_RL32("GEOX"))) {
for (int p = 0; p < 3; p++) {
int h = AV_CEIL_RSHIFT(pict->height, !!p);
pict->data[p] += (h - 1) * pict->linesize[p];
pict->linesize[p] *= -1;
}
}
*got_frame = 1;
}
if (slice_ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
return slice_ret;
else
return get_consumed_bytes(s, buf_size);
}
static const AVCodecHWConfigInternal *const h263_hw_config_list[] = {
#if CONFIG_H263_VAAPI_HWACCEL
HWACCEL_VAAPI(h263),
#endif
#if CONFIG_MPEG4_NVDEC_HWACCEL
HWACCEL_NVDEC(mpeg4),
#endif
#if CONFIG_MPEG4_VDPAU_HWACCEL
HWACCEL_VDPAU(mpeg4),
#endif
#if CONFIG_H263_VIDEOTOOLBOX_HWACCEL
HWACCEL_VIDEOTOOLBOX(h263),
#endif
NULL
};
const FFCodec ff_h263_decoder = {
.p.name = "h263",
CODEC_LONG_NAME("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"),
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_H263,
.priv_data_size = sizeof(MpegEncContext),
.init = ff_h263_decode_init,
FF_CODEC_DECODE_CB(ff_h263_decode_frame),
.close = ff_mpv_decode_close,
.p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 |
AV_CODEC_CAP_DELAY,
avcodec/mpegpicture: Make MPVPicture refcounted Up until now, an initialized MpegEncContext had an array of MPVPictures (way more than were ever needed) and the MPVPicture* contained in the MPVWorkPictures as well as the input_picture and reordered_input_picture arrays (for the encoder) pointed into this array. Several of the pointers could point to the same slot and because there was no reference counting involved, one had to check for aliasing before unreferencing. Furthermore, given that these pointers were not ownership pointers the pointers were often simply reset without unreferencing the slot (happened e.g. for the RV30 and RV40 decoders) or there were moved without resetting the src pointer (happened for the encoders where the entries in the input_picture and reordered_input_picture arrays were not reset). Instead actually releasing these pictures was performed by looping over the whole array and checking which one of the entries needed to be kept. Given that the array had way too many slots (36), this meant that more than 30 MPVPictures have been unnecessarily unreferenced in every ff_mpv_frame_start(); something similar happened for the encoder. This commit changes this by making the MPVPictures refcounted via the RefStruct API. The MPVPictures itself are part of a pool so that this does not entail constant allocations; instead, the amount of allocations actually goes down, because the earlier code used such a large array of MPVPictures (36 entries) and allocated an AVFrame for every one of these on every ff_mpv_common_init(). In fact, the pool is only freed when closing the codec, so that reinitializations don't lead to new allocations (this avoids having to sync the pool in update_thread_context). Making MPVPictures refcounted also has another key benefit: It makes it possible to directly share them across threads (when using frame-threaded decoding), eliminating ugly code with underlying av_frame_ref()'s; sharing these pictures can't fail any more. The pool is allocated in ff_mpv_decode_init() for decoders, which therefore can fail now. This and the fact that the pool is not unreferenced in ff_mpv_common_end() also necessitated to mark several mpegvideo-decoders with the FF_CODEC_CAP_INIT_CLEANUP flag. *: This also means that there is no good reason any more for ff_mpv_common_frame_size_change() to exist. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-15 21:34:43 +02:00
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
.flush = ff_mpeg_flush,
.p.max_lowres = 3,
.hw_configs = h263_hw_config_list,
};
const FFCodec ff_h263p_decoder = {
.p.name = "h263p",
CODEC_LONG_NAME("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"),
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_H263P,
.priv_data_size = sizeof(MpegEncContext),
.init = ff_h263_decode_init,
FF_CODEC_DECODE_CB(ff_h263_decode_frame),
.close = ff_mpv_decode_close,
.p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 |
AV_CODEC_CAP_DELAY,
avcodec/mpegpicture: Make MPVPicture refcounted Up until now, an initialized MpegEncContext had an array of MPVPictures (way more than were ever needed) and the MPVPicture* contained in the MPVWorkPictures as well as the input_picture and reordered_input_picture arrays (for the encoder) pointed into this array. Several of the pointers could point to the same slot and because there was no reference counting involved, one had to check for aliasing before unreferencing. Furthermore, given that these pointers were not ownership pointers the pointers were often simply reset without unreferencing the slot (happened e.g. for the RV30 and RV40 decoders) or there were moved without resetting the src pointer (happened for the encoders where the entries in the input_picture and reordered_input_picture arrays were not reset). Instead actually releasing these pictures was performed by looping over the whole array and checking which one of the entries needed to be kept. Given that the array had way too many slots (36), this meant that more than 30 MPVPictures have been unnecessarily unreferenced in every ff_mpv_frame_start(); something similar happened for the encoder. This commit changes this by making the MPVPictures refcounted via the RefStruct API. The MPVPictures itself are part of a pool so that this does not entail constant allocations; instead, the amount of allocations actually goes down, because the earlier code used such a large array of MPVPictures (36 entries) and allocated an AVFrame for every one of these on every ff_mpv_common_init(). In fact, the pool is only freed when closing the codec, so that reinitializations don't lead to new allocations (this avoids having to sync the pool in update_thread_context). Making MPVPictures refcounted also has another key benefit: It makes it possible to directly share them across threads (when using frame-threaded decoding), eliminating ugly code with underlying av_frame_ref()'s; sharing these pictures can't fail any more. The pool is allocated in ff_mpv_decode_init() for decoders, which therefore can fail now. This and the fact that the pool is not unreferenced in ff_mpv_common_end() also necessitated to mark several mpegvideo-decoders with the FF_CODEC_CAP_INIT_CLEANUP flag. *: This also means that there is no good reason any more for ff_mpv_common_frame_size_change() to exist. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2023-10-15 21:34:43 +02:00
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
.flush = ff_mpeg_flush,
.p.max_lowres = 3,
.hw_configs = h263_hw_config_list,
};