|
@@ -25,6 +25,7 @@
|
|
|
#include "config_components.h"
|
|
#include "config_components.h"
|
|
|
|
|
|
|
|
#include "libavutil/internal.h"
|
|
#include "libavutil/internal.h"
|
|
|
|
|
+#include "libavutil/mem.h"
|
|
|
#include "libavutil/opt.h"
|
|
#include "libavutil/opt.h"
|
|
|
#include "libavutil/thread.h"
|
|
#include "libavutil/thread.h"
|
|
|
#include "codec_internal.h"
|
|
#include "codec_internal.h"
|
|
@@ -3463,8 +3464,8 @@ static int decode_studiovisualobject(Mpeg4DecContext *ctx, GetBitContext *gb)
|
|
|
* FRAME_SKIPPED if a not coded VOP is found
|
|
* FRAME_SKIPPED if a not coded VOP is found
|
|
|
* 0 else
|
|
* 0 else
|
|
|
*/
|
|
*/
|
|
|
-int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb,
|
|
|
|
|
- int header, int parse_only)
|
|
|
|
|
|
|
+int ff_mpeg4_parse_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb,
|
|
|
|
|
+ int header, int parse_only)
|
|
|
{
|
|
{
|
|
|
MpegEncContext *s = &ctx->m;
|
|
MpegEncContext *s = &ctx->m;
|
|
|
unsigned startcode, v;
|
|
unsigned startcode, v;
|
|
@@ -3621,16 +3622,50 @@ end:
|
|
|
return decode_vop_header(ctx, gb, parse_only);
|
|
return decode_vop_header(ctx, gb, parse_only);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+int ff_mpeg4_decode_picture_header(MpegEncContext *s)
|
|
|
|
|
+{
|
|
|
|
|
+ Mpeg4DecContext *const ctx = (Mpeg4DecContext*)s;
|
|
|
|
|
+
|
|
|
|
|
+ if (ctx->bitstream_buffer_size) {
|
|
|
|
|
+ int buf_size = get_bits_left(&s->gb) / 8U;
|
|
|
|
|
+ int bitstream_buffer_size = ctx->bitstream_buffer_size;
|
|
|
|
|
+ const uint8_t *buf = s->gb.buffer;
|
|
|
|
|
+
|
|
|
|
|
+ if (s->divx_packed) {
|
|
|
|
|
+ for (int 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");
|
|
|
|
|
+ bitstream_buffer_size = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ctx->bitstream_buffer_size = 0;
|
|
|
|
|
+ if (bitstream_buffer_size && (s->divx_packed || buf_size <= MAX_NVOP_SIZE)) {// divx 5.01+/xvid frame reorder
|
|
|
|
|
+ int ret = init_get_bits8(&s->gb, ctx->bitstream_buffer,
|
|
|
|
|
+ bitstream_buffer_size);
|
|
|
|
|
+ if (ret < 0)
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ff_mpeg4_parse_picture_header(ctx, &s->gb, 0, 0);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
|
|
int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
|
|
|
{
|
|
{
|
|
|
Mpeg4DecContext *ctx = avctx->priv_data;
|
|
Mpeg4DecContext *ctx = avctx->priv_data;
|
|
|
MpegEncContext *s = &ctx->m;
|
|
MpegEncContext *s = &ctx->m;
|
|
|
|
|
|
|
|
|
|
+ av_assert1(ctx->bitstream_buffer_size == 0);
|
|
|
|
|
+
|
|
|
/* divx 5.01+ bitstream reorder stuff */
|
|
/* divx 5.01+ bitstream reorder stuff */
|
|
|
/* Since this clobbers the input buffer and hwaccel codecs still need the
|
|
/* Since this clobbers the input buffer and hwaccel codecs still need the
|
|
|
* data during hwaccel->end_frame we should not do this any earlier */
|
|
* data during hwaccel->end_frame we should not do this any earlier */
|
|
|
if (s->divx_packed) {
|
|
if (s->divx_packed) {
|
|
|
- int current_pos = s->gb.buffer == s->bitstream_buffer ? 0 : (get_bits_count(&s->gb) >> 3);
|
|
|
|
|
|
|
+ int current_pos = s->gb.buffer == ctx->bitstream_buffer ? 0 : (get_bits_count(&s->gb) >> 3);
|
|
|
int startcode_found = 0;
|
|
int startcode_found = 0;
|
|
|
|
|
|
|
|
if (buf_size - current_pos > 7) {
|
|
if (buf_size - current_pos > 7) {
|
|
@@ -3654,16 +3689,16 @@ int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
|
|
|
"Consider using the mpeg4_unpack_bframes bitstream filter without encoding but stream copy to fix it.\n");
|
|
"Consider using the mpeg4_unpack_bframes bitstream filter without encoding but stream copy to fix it.\n");
|
|
|
ctx->showed_packed_warning = 1;
|
|
ctx->showed_packed_warning = 1;
|
|
|
}
|
|
}
|
|
|
- av_fast_padded_malloc(&s->bitstream_buffer,
|
|
|
|
|
- &s->allocated_bitstream_buffer_size,
|
|
|
|
|
|
|
+ av_fast_padded_malloc(&ctx->bitstream_buffer,
|
|
|
|
|
+ &ctx->allocated_bitstream_buffer_size,
|
|
|
buf_size - current_pos);
|
|
buf_size - current_pos);
|
|
|
- if (!s->bitstream_buffer) {
|
|
|
|
|
- s->bitstream_buffer_size = 0;
|
|
|
|
|
|
|
+ if (!ctx->bitstream_buffer) {
|
|
|
|
|
+ ctx->bitstream_buffer_size = 0;
|
|
|
return AVERROR(ENOMEM);
|
|
return AVERROR(ENOMEM);
|
|
|
}
|
|
}
|
|
|
- memcpy(s->bitstream_buffer, buf + current_pos,
|
|
|
|
|
|
|
+ memcpy(ctx->bitstream_buffer, buf + current_pos,
|
|
|
buf_size - current_pos);
|
|
buf_size - current_pos);
|
|
|
- s->bitstream_buffer_size = buf_size - current_pos;
|
|
|
|
|
|
|
+ ctx->bitstream_buffer_size = buf_size - current_pos;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -3715,17 +3750,17 @@ static int mpeg4_update_thread_context(AVCodecContext *dst,
|
|
|
memcpy(s->sprite_shift, s1->sprite_shift, sizeof(s1->sprite_shift));
|
|
memcpy(s->sprite_shift, s1->sprite_shift, sizeof(s1->sprite_shift));
|
|
|
memcpy(s->sprite_traj, s1->sprite_traj, sizeof(s1->sprite_traj));
|
|
memcpy(s->sprite_traj, s1->sprite_traj, sizeof(s1->sprite_traj));
|
|
|
|
|
|
|
|
- if (s1->m.bitstream_buffer) {
|
|
|
|
|
- av_fast_padded_malloc(&s->m.bitstream_buffer,
|
|
|
|
|
- &s->m.allocated_bitstream_buffer_size,
|
|
|
|
|
- s1->m.bitstream_buffer_size);
|
|
|
|
|
- if (!s->m.bitstream_buffer) {
|
|
|
|
|
- s->m.bitstream_buffer_size = 0;
|
|
|
|
|
|
|
+ if (s1->bitstream_buffer) {
|
|
|
|
|
+ av_fast_padded_malloc(&s->bitstream_buffer,
|
|
|
|
|
+ &s->allocated_bitstream_buffer_size,
|
|
|
|
|
+ s1->bitstream_buffer_size);
|
|
|
|
|
+ if (!s->bitstream_buffer) {
|
|
|
|
|
+ s->bitstream_buffer_size = 0;
|
|
|
return AVERROR(ENOMEM);
|
|
return AVERROR(ENOMEM);
|
|
|
}
|
|
}
|
|
|
- s->m.bitstream_buffer_size = s1->m.bitstream_buffer_size;
|
|
|
|
|
- memcpy(s->m.bitstream_buffer, s1->m.bitstream_buffer,
|
|
|
|
|
- s1->m.bitstream_buffer_size);
|
|
|
|
|
|
|
+ s->bitstream_buffer_size = s1->bitstream_buffer_size;
|
|
|
|
|
+ memcpy(s->bitstream_buffer, s1->bitstream_buffer,
|
|
|
|
|
+ s1->bitstream_buffer_size);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!init && s1->xvid_build >= 0)
|
|
if (!init && s1->xvid_build >= 0)
|
|
@@ -3825,12 +3860,30 @@ static av_cold int decode_init(AVCodecContext *avctx)
|
|
|
GetBitContext gb;
|
|
GetBitContext gb;
|
|
|
|
|
|
|
|
if (init_get_bits8(&gb, avctx->extradata, avctx->extradata_size) >= 0)
|
|
if (init_get_bits8(&gb, avctx->extradata, avctx->extradata_size) >= 0)
|
|
|
- ff_mpeg4_decode_picture_header(ctx, &gb, 1, 0);
|
|
|
|
|
|
|
+ ff_mpeg4_parse_picture_header(ctx, &gb, 1, 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static av_cold void mpeg4_flush(AVCodecContext *avctx)
|
|
|
|
|
+{
|
|
|
|
|
+ Mpeg4DecContext *const ctx = avctx->priv_data;
|
|
|
|
|
+
|
|
|
|
|
+ ctx->bitstream_buffer_size = 0;
|
|
|
|
|
+ ff_mpeg_flush(avctx);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static av_cold int mpeg4_close(AVCodecContext *avctx)
|
|
|
|
|
+{
|
|
|
|
|
+ Mpeg4DecContext *const ctx = avctx->priv_data;
|
|
|
|
|
+
|
|
|
|
|
+ ctx->bitstream_buffer_size = 0;
|
|
|
|
|
+ av_freep(&ctx->bitstream_buffer);
|
|
|
|
|
+
|
|
|
|
|
+ return ff_mpv_decode_close(avctx);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
#define OFFSET(x) offsetof(MpegEncContext, x)
|
|
#define OFFSET(x) offsetof(MpegEncContext, x)
|
|
|
#define FLAGS AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY
|
|
#define FLAGS AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY
|
|
|
static const AVOption mpeg4_options[] = {
|
|
static const AVOption mpeg4_options[] = {
|
|
@@ -3854,12 +3907,12 @@ const FFCodec ff_mpeg4_decoder = {
|
|
|
.priv_data_size = sizeof(Mpeg4DecContext),
|
|
.priv_data_size = sizeof(Mpeg4DecContext),
|
|
|
.init = decode_init,
|
|
.init = decode_init,
|
|
|
FF_CODEC_DECODE_CB(ff_h263_decode_frame),
|
|
FF_CODEC_DECODE_CB(ff_h263_decode_frame),
|
|
|
- .close = ff_mpv_decode_close,
|
|
|
|
|
|
|
+ .close = mpeg4_close,
|
|
|
.p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 |
|
|
.p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 |
|
|
|
AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS,
|
|
AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS,
|
|
|
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
|
|
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
|
|
|
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
|
|
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
|
|
|
- .flush = ff_mpeg_flush,
|
|
|
|
|
|
|
+ .flush = mpeg4_flush,
|
|
|
.p.max_lowres = 3,
|
|
.p.max_lowres = 3,
|
|
|
.p.profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles),
|
|
.p.profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles),
|
|
|
UPDATE_THREAD_CONTEXT(mpeg4_update_thread_context),
|
|
UPDATE_THREAD_CONTEXT(mpeg4_update_thread_context),
|