[PATCH] Fix compilation against latest FFmpeg.
Only for MPlayer, mencoder needs more changes. --- Makefile | 4 +- av_helpers.c | 91 +++++++++++++++++++++++++++++++++++++ av_helpers.h | 4 ++ libmpcodecs/ad_spdif.c | 4 +- libmpcodecs/vd_ffmpeg.c | 8 +++- libmpcodecs/vf.c | 2 +- libmpcodecs/vf_lavc.c | 35 +++++++------- libmpcodecs/vf_screenshot.c | 29 ++++++------ libmpdemux/demux_lavf.c | 13 ++++-- sub/av_sub.c | 14 +++--- 10 files changed, 154 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index 56fb7780e..94ef50367 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,9 @@ SRCS_COMMON-$(CONFIG_VF_LAVFI) += libmpcodecs/vf_lavfi.c SRCS_COMMON-$(FFMPEG_A) += libmpcodecs/vf_fspp.c \ libmpcodecs/vf_qp.c \ libmpcodecs/vf_spp.c \ - libmpcodecs/vf_uspp.c \ + +# needs update for missing coded_frame +#libmpcodecs/vf_uspp.c \ SRCS_COMMON-$(FREETYPE) += sub/font_load_ft.c SRCS_COMMON-$(FTP) += stream/stream_ftp.c diff --git a/av_helpers.c b/av_helpers.c index 2d543b314..a4e245a19 100644 --- a/av_helpers.c +++ b/av_helpers.c @@ -20,6 +20,7 @@ #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" +#include "libavutil/intreadwrite.h" #include "mp_msg.h" #include "av_helpers.h" #include "libaf/reorder_ch.h" @@ -165,3 +166,93 @@ int lavc_encode_audio(AVCodecContext *ctx, void *src, int src_len, void *dst, in } return 0; } + +#define MERGE_MARKER 0x8c4d9d108e25e9feULL + +static void bytestream_put_buffer(uint8_t **b, const uint8_t *src, unsigned int size) +{ + memcpy(*b, src, size); + *b += size; +} + +int mp_packet_merge_side_data(AVPacket *pkt){ + if(pkt->side_data_elems){ + AVBufferRef *buf; + int i; + uint8_t *p; + uint64_t size= pkt->size + 8LL + AV_INPUT_BUFFER_PADDING_SIZE; + AVPacket old= *pkt; + for (i=0; i<old.side_data_elems; i++) { + size += old.side_data[i].size + 5LL; + } + if (size > INT_MAX) + return AVERROR(EINVAL); + buf = av_buffer_alloc(size); + if (!buf) + return AVERROR(ENOMEM); + pkt->buf = buf; + pkt->data = p = buf->data; + pkt->size = size - AV_INPUT_BUFFER_PADDING_SIZE; + bytestream_put_buffer(&p, old.data, old.size); + for (i=old.side_data_elems-1; i>=0; i--) { + bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size); + AV_WB32(p, old.side_data[i].size); + p += 4; + *p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128); + } + AV_WB64(p, MERGE_MARKER); + p += 8; + memset(p, 0, AV_INPUT_BUFFER_PADDING_SIZE); + av_packet_unref(&old); + pkt->side_data_elems = 0; + pkt->side_data = NULL; + return 1; + } + return 0; +} + +int mp_packet_split_side_data(AVPacket *pkt){ + if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == MERGE_MARKER){ + int i; + unsigned int size; + uint8_t *p; + + p = pkt->data + pkt->size - 8 - 5; + for (i=1; ; i++){ + size = AV_RB32(p); + if (size>INT_MAX - 5 || p - pkt->data < size) + return 0; + if (p[4]&128) + break; + if (p - pkt->data < size + 5) + return 0; + p-= size+5; + } + + if (i > AV_PKT_DATA_NB) + return AVERROR(ERANGE); + + pkt->side_data = av_malloc_array(i, sizeof(*pkt->side_data)); + if (!pkt->side_data) + return AVERROR(ENOMEM); + + p= pkt->data + pkt->size - 8 - 5; + for (i=0; ; i++){ + size= AV_RB32(p); + pkt->side_data[i].data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); + pkt->side_data[i].size = size; + pkt->side_data[i].type = p[4]&127; + if (!pkt->side_data[i].data) + return AVERROR(ENOMEM); + memcpy(pkt->side_data[i].data, p-size, size); + pkt->size -= size + 5; + if(p[4]&128) + break; + p-= size+5; + } + pkt->size -= 8; + pkt->side_data_elems = i+1; + return 1; + } + return 0; +} diff --git a/av_helpers.h b/av_helpers.h index 9c8321305..5bef2aa63 100644 --- a/av_helpers.h +++ b/av_helpers.h @@ -22,9 +22,13 @@ #define MPLAYER_AV_HELPERS_H struct AVCodecContext; +struct AVFrame; +struct AVPacket; void init_avcodec(void); void init_avformat(void); int lavc_encode_audio(struct AVCodecContext *ctx, void *src, int src_len, void *dst, int dst_len); +int mp_packet_merge_side_data(struct AVPacket *pkt); +int mp_packet_split_side_data(struct AVPacket *pkt); #endif /* MPLAYER_AV_HELPERS_H */ diff --git a/libmpcodecs/ad_spdif.c b/libmpcodecs/ad_spdif.c index 8ee472429..d49e4f51b 100644 --- a/libmpcodecs/ad_spdif.c +++ b/libmpcodecs/ad_spdif.c @@ -126,7 +126,7 @@ static int init(sh_audio_t *sh) lavf_ctx->start_time = AV_NOPTS_VALUE; for (i = 0; fmt_id_type[i].name; i++) { if (!strcmp(codec_idx2str(sh->codec->dll_idx), fmt_id_type[i].name)) { - lavf_ctx->streams[0]->codec->codec_id = fmt_id_type[i].id; + lavf_ctx->streams[0]->codecpar->codec_id = fmt_id_type[i].id; break; } } @@ -161,7 +161,7 @@ static int init(sh_audio_t *sh) } sh->ds->buffer_pos -= in_size; - switch (lavf_ctx->streams[0]->codec->codec_id) { + switch (lavf_ctx->streams[0]->codecpar->codec_id) { case AV_CODEC_ID_AAC: spdif_ctx->iec61937_packet_size = 16384; sh->sample_format = AF_FORMAT_IEC61937_LE; diff --git a/libmpcodecs/vd_ffmpeg.c b/libmpcodecs/vd_ffmpeg.c index cb23d07b4..6e30c51f6 100644 --- a/libmpcodecs/vd_ffmpeg.c +++ b/libmpcodecs/vd_ffmpeg.c @@ -902,7 +902,7 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){ pkt.size = len; // Necessary to decode e.g. CorePNG and ZeroCodec correctly pkt.flags = (sh->ds->flags & 1) ? AV_PKT_FLAG_KEY : 0; - av_packet_split_side_data(&pkt); + mp_packet_split_side_data(&pkt); if (av_packet_get_side_data(&pkt, AV_PKT_DATA_PALETTE, NULL)) ctx->palette_sent = 1; if (!ctx->palette_sent && sh->bih && sh->bih->biBitCount <= 8) { @@ -977,6 +977,8 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){ // average MB quantizer { +// TODO: still possible in new FFmpeg API? +#if 0 int x, y; int w = ((avctx->width << lavc_param_lowres)+15) >> 4; int h = ((avctx->height << lavc_param_lowres)+15) >> 4; @@ -989,6 +991,7 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){ q += qstride; } quality /= w * h; +#endif } all_len+=len; @@ -1079,7 +1082,8 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){ swap_palette(mpi->planes[1]); #endif /* to comfirm with newer lavc style */ - mpi->qscale = av_frame_get_qp_table(pic, &mpi->qstride, &mpi->qscale_type); +// TODO: still possible in new FFmpeg API? +// mpi->qscale = av_frame_get_qp_table(pic, &mpi->qstride, &mpi->qscale_type); mpi->pict_type=pic->pict_type; mpi->fields = MP_IMGFIELD_ORDERED; if(pic->interlaced_frame) mpi->fields |= MP_IMGFIELD_INTERLACED; diff --git a/libmpcodecs/vf.c b/libmpcodecs/vf.c index 563632cb9..f4f172a76 100644 --- a/libmpcodecs/vf.c +++ b/libmpcodecs/vf.c @@ -197,7 +197,7 @@ static const vf_info_t* const filter_list[]={ &vf_info_hue, #ifdef CONFIG_FFMPEG_A &vf_info_spp, - &vf_info_uspp, +// &vf_info_uspp, // TODO: does not currently build &vf_info_fspp, &vf_info_qp, // &vf_info_mcdeint, //TODO: vf_mcdeint is deactivated because it doesn't build after latest FFmpeg major bumps diff --git a/libmpcodecs/vf_lavc.c b/libmpcodecs/vf_lavc.c index 9acd695d7..c5252a8f0 100644 --- a/libmpcodecs/vf_lavc.c +++ b/libmpcodecs/vf_lavc.c @@ -33,12 +33,12 @@ struct vf_priv_s { - unsigned char* outbuf; - int outbuf_size; AVCodecContext* context; AVFrame* pic; - AVCodec* codec; + const AVCodec* codec; vo_mpegpes_t pes; + AVPacket *pkt; + int pkt_has_ref; }; #define lavc_venc_context (*vf->priv->context) @@ -69,10 +69,7 @@ static int config(struct vf_instance *vf, } } - free(vf->priv->outbuf); - - vf->priv->outbuf_size=10000+width*height; // must be enough! - vf->priv->outbuf = malloc(vf->priv->outbuf_size); + if (vf->priv->pkt_has_ref) av_packet_unref(vf->priv->pkt); if (avcodec_open2(&lavc_venc_context, vf->priv->codec, NULL) != 0) { mp_msg(MSGT_MENCODER,MSGL_ERR,MSGTR_CantOpenCodec); @@ -84,10 +81,9 @@ static int config(struct vf_instance *vf, static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){ mp_image_t* dmpi; - int out_size; AVFrame *pic= vf->priv->pic; - int ret, got_pkt; - AVPacket pkt; + AVPacket *pkt = vf->priv->pkt; + int ret; pic->data[0]=mpi->planes[0]; pic->data[1]=mpi->planes[1]; @@ -96,21 +92,21 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double pic->linesize[1]=mpi->stride[1]; pic->linesize[2]=mpi->stride[2]; - av_init_packet(&pkt); - pkt.data = vf->priv->outbuf; - pkt.size = vf->priv->outbuf_size; - ret = avcodec_encode_video2(&lavc_venc_context, &pkt, pic, &got_pkt); + if (vf->priv->pkt_has_ref) av_packet_unref(pkt); + ret = avcodec_send_frame(&lavc_venc_context, pic); + if (ret >= 0) { + ret = avcodec_receive_packet(&lavc_venc_context, pkt); + } + vf->priv->pkt_has_ref = ret >= 0; - if(ret<=0) return 1; - if(!got_pkt) return 1; - out_size = pkt.size; + if(ret<0) return 1; dmpi=vf_get_image(vf->next,IMGFMT_MPEGPES, MP_IMGTYPE_EXPORT, 0, mpi->w, mpi->h); - vf->priv->pes.data=vf->priv->outbuf; - vf->priv->pes.size=out_size; + vf->priv->pes.data=pkt->data; + vf->priv->pes.size=pkt->size; vf->priv->pes.id=0x1E0; vf->priv->pes.timestamp=-1; // dunno @@ -151,6 +147,7 @@ static int vf_open(vf_instance_t *vf, char *args){ vf->priv->context=avcodec_alloc_context3(vf->priv->codec); vf->priv->pic = av_frame_alloc(); + vf->priv->pkt = av_packet_alloc(); // TODO: parse args -> if(args) sscanf(args, "%d:%f", &p_quality, &p_fps); diff --git a/libmpcodecs/vf_screenshot.c b/libmpcodecs/vf_screenshot.c index 9aafac3a2..e8b87fa91 100644 --- a/libmpcodecs/vf_screenshot.c +++ b/libmpcodecs/vf_screenshot.c @@ -49,10 +49,9 @@ struct vf_priv_s { int shot, store_slices; int dw, dh; AVFrame *pic; + AVPacket *pkt; struct SwsContext *ctx; AVCodecContext *avctx; - uint8_t *outbuffer; - int outbuffer_size; }; //===========================================================================// @@ -75,7 +74,6 @@ static int config(struct vf_instance *vf, vf->priv->ctx=sws_getContextFromCmdLine(width, height, outfmt, d_width, d_height, IMGFMT_RGB24); - av_fast_malloc(&vf->priv->outbuffer, &vf->priv->outbuffer_size, d_width * d_height * 3 * 2); if (!vf->priv->avctx) { vf->priv->avctx = avcodec_alloc_context3(NULL); vf->priv->avctx->pix_fmt = AV_PIX_FMT_RGB24; @@ -106,17 +104,21 @@ static void write_png(struct vf_priv_s *priv) { char *fname = priv->fname; FILE * fp; - AVPacket pkt; - int res, got_pkt; + AVPacket *pkt = priv->pkt; + int res; - av_init_packet(&pkt); - pkt.data = priv->outbuffer; - pkt.size = priv->outbuffer_size; priv->pic->width = priv->avctx->width; priv->pic->height = priv->avctx->height; priv->pic->format = priv->avctx->pix_fmt; - res = avcodec_encode_video2(priv->avctx, &pkt, priv->pic, &got_pkt); - if (res < 0 || !got_pkt || pkt.size <= 0) { + res = avcodec_send_frame(priv->avctx, priv->pic); + if (res >= 0) { + res = avcodec_receive_packet(priv->avctx, pkt); + if (res == AVERROR(EAGAIN)) { + avcodec_send_frame(priv->avctx, NULL); + res = avcodec_receive_packet(priv->avctx, pkt); + } + } + if (res < 0 || pkt->size <= 0) { mp_msg(MSGT_VFILTER,MSGL_ERR,"\nFailed to encode screenshot %s!\n", fname); return; } @@ -127,7 +129,8 @@ static void write_png(struct vf_priv_s *priv) return; } - fwrite(priv->outbuffer, pkt.size, 1, fp); + fwrite(pkt->data, pkt->size, 1, fp); + av_packet_unref(pkt); fclose (fp); mp_msg(MSGT_VFILTER,MSGL_INFO,"*** screenshot '%s' ***\n",priv->fname); @@ -281,7 +284,7 @@ static void uninit(vf_instance_t *vf) if(vf->priv->ctx) sws_freeContext(vf->priv->ctx); av_freep(&vf->priv->pic->data[0]); av_frame_free(&vf->priv->pic); - av_freep(&vf->priv->outbuffer); + av_packet_free(&vf->priv->pkt); free(vf->priv->prefix); free(vf->priv); } @@ -298,8 +301,8 @@ static int vf_open(vf_instance_t *vf, char *args) vf->uninit=uninit; vf->priv = calloc(1, sizeof(struct vf_priv_s)); vf->priv->pic = av_frame_alloc(); + vf->priv->pkt = av_packet_alloc(); vf->priv->prefix = strdup(args ? args : "shot"); - avcodec_register_all(); if (!avcodec_find_encoder(AV_CODEC_ID_PNG)) { mp_msg(MSGT_VFILTER, MSGL_FATAL, "Could not find libavcodec PNG encoder\n"); return 0; diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c index d3e6e31ae..db18726db 100644 --- a/libmpdemux/demux_lavf.c +++ b/libmpdemux/demux_lavf.c @@ -68,7 +68,7 @@ const m_option_t lavfdopts_conf[] = { #define BIO_BUFFER_SIZE 32768 typedef struct lavf_priv { - AVInputFormat *avif; + const AVInputFormat *avif; AVFormatContext *avfc; AVIOContext *pb; int audio_streams; @@ -366,7 +366,7 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) { if (demuxer->audio->id != i) st->discard= AVDISCARD_ALL; if (priv->audio_streams == 0) { - int rg_size; + size_t rg_size; AVReplayGain *rg = (AVReplayGain*)av_stream_get_side_data(st, AV_PKT_DATA_REPLAYGAIN, &rg_size); if (rg && rg_size >= sizeof(*rg)) { priv->r_gain = rg->track_gain / 10000; @@ -420,9 +420,12 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) { if (st->time_base.den) { /* if container has time_base, use that */ sh_video->video.dwRate= st->time_base.den; sh_video->video.dwScale= st->time_base.num; +#if 0 } else { + // not available in latest FFmpeg API, ok to just remove? sh_video->video.dwRate= st->codec->time_base.den; sh_video->video.dwScale= st->codec->time_base.num; +#endif } sh_video->fps=av_q2d(st->r_frame_rate); sh_video->frametime=1/av_q2d(st->r_frame_rate); @@ -527,7 +530,7 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) { st->discard= AVDISCARD_ALL; } if (stream_type) { - AVCodec *avc = avcodec_find_decoder(codec->codec_id); + const AVCodec *avc = avcodec_find_decoder(codec->codec_id); const char *codec_name = avc ? avc->name : "unknown"; if (!avc && *stream_type == 's' && demuxer->s_streams[i]) codec_name = sh_sub_type2str(((sh_sub_t *)demuxer->s_streams[i])->type); @@ -707,7 +710,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds){ } sh = ds->sh; if (sh && sh->bih) { - int size = 0; + size_t size = 0; const uint8_t *pal = av_packet_get_side_data(&pkt, AV_PKT_DATA_PALETTE, &size); if (pal && size) memcpy(((uint8_t *)sh->bih) + sh->bih->biSize, pal, FFMIN(size, 1024)); @@ -721,7 +724,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds){ return 1; } - av_packet_merge_side_data(&pkt); + mp_packet_merge_side_data(&pkt); dp=new_demux_packet(pkt.size); memcpy(dp->buffer, pkt.data, pkt.size); diff --git a/sub/av_sub.c b/sub/av_sub.c index aa95202e5..fcb98a078 100644 --- a/sub/av_sub.c +++ b/sub/av_sub.c @@ -43,9 +43,9 @@ static void avsub_to_spudec(AVSubtitleRect **rects, int num_rects, if (num_rects == 1) { spudec_set_paletted(vo_spudec, - rects[0]->pict.data[0], - rects[0]->pict.linesize[0], - rects[0]->pict.data[1], + rects[0]->data[0], + rects[0]->linesize[0], + rects[0]->data[1], rects[0]->x, rects[0]->y, rects[0]->w, @@ -66,9 +66,9 @@ static void avsub_to_spudec(AVSubtitleRect **rects, int num_rects, spudec_packet_clear(packet); for (i = 0; i < num_rects; i++) spudec_packet_fill(packet, - rects[i]->pict.data[0], - rects[i]->pict.linesize[0], - rects[i]->pict.data[1], + rects[i]->data[0], + rects[i]->linesize[0], + rects[i]->data[1], rects[i]->x - xmin, rects[i]->y - ymin, rects[i]->w, @@ -105,7 +105,7 @@ int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, pkt.size = *size; pkt.pts = *pts * 1000; if (*pts != MP_NOPTS_VALUE && *endpts != MP_NOPTS_VALUE) - pkt.convergence_duration = (*endpts - *pts) * 1000; + pkt.duration = (*endpts - *pts) * 1000; if (!ctx) { AVCodec *sub_codec; init_avcodec(); -- 2.31.1
Hi all, I have tested this patch against 2 FFmpeg revisions. Revision before the Major Bumps ------------------------------- commit 45fc214ebfcdf36b935632edda54aee9e8745550 CommitDate: Tue Apr 27 09:18:41 2021 +0530 avformat/adtsenc: clarify option help MPlayer builds with and without the patches against this FFmpeg revision. I get mostly identical results on `make fatetest`, with or without this patch. There is sometimes a small number of samples that differs because of I think tests that don't always yield the same results with threaded decoding. One problem I observe unrelated to this patch is a failed assertion and crash: ./mplayer "$FATE_SAMPLES"/vp3/offset_test.ogv Playing a few random videos looks fine to me. Revision after the Major Bumps ------------------------------ commit 8b83a4a885e3b92bd09354d6cb182fca47f80973 CommitDate: Fri Apr 30 10:24:32 2021 +0200 avutil/mem: Also poison new av_realloc-allocated blocks Now I get more than 500 checksum changes on `make fatetest`, lots of them look worrying because there are simply no decoded frames and at all. This is probably related with failures like this: ./mplayer "$FATE_SAMPLES"/h264-conformance/MR8_BT_B.h264 MPlayer UNKNOWN-9 (C) 2000-2021 MPlayer Team Playing /home/beastd/devel/fate/samples//h264-conformance/MR8_BT_B.h264. libavformat version 59.0.100 (internal) libavformat file format detected. [Eval @ 0x55e772033360]Undefined constant or missing '(' in 'keepside' [h264 @ 0x55e771fa0920]Unable to parse option value "keepside" [h264 @ 0x55e771fa0920]Error setting option fflags to value +keepside. LAVF_header: av_open_input_stream() failed Exiting... (End of file) Others are worrying because previously differently decoded frames become all the same, like in this example: ./mplayer "$FATE_SAMPLES"/mov/spherical.mov MPlayer UNKNOWN-9 (C) 2000-2021 MPlayer Team Playing /home/beastd/devel/fate/samples//mov/spherical.mov. libavformat version 59.0.100 (internal) libavformat file format detected. [Eval @ 0x55946f388360]Undefined constant or missing '(' in 'keepside' [mov,mp4,m4a,3gp,3g2,mj2 @ 0x55946f2f5920]Unable to parse option value "keepside" [mov,mp4,m4a,3gp,3g2,mj2 @ 0x55946f2f5920]Error setting option fflags to value +keepside. LAVF_header: av_open_input_stream() failed ISO: File Type Major Brand: ISO/IEC 14496-1 (MPEG-4 system) v2 Quicktime/MOV file format detected. [mov] Video stream found, -vid 0 VIDEO: [avc1] 1920x1080 24bpp 25.000 fps 0.0 kbps ( 0.0 kbyte/s) ========================================================================== Opening video decoder: [ffmpeg] FFmpeg's libavcodec codec family libavcodec version 59.0.100 (internal) Selected video codec: [ffh264] vfm: ffmpeg (FFmpeg H.264) ========================================================================== Load subtitles in /home/beastd/devel/fate/samples//mov/ Audio: no sound Starting playback... [h264 @ 0x55946f3291a0]co located POCs unavailable [h264 @ 0x55946f3291a0]co located POCs unavailable Could not find matching colorspace - retrying with -vf scale... Opening video filter: [scale] Movie-Aspect is undefined - no prescaling applied. [swscaler @ 0x55946f351140]bicubic scaler, from yuv444p to yuv420p using MMXEXT VO: [vdpau] 1920x1080 => 1920x1080 Planar YV12 [ASPECT] Warning: No suitable new res found! [ASPECT] Warning: No suitable new res found! V: 4.7 118/118 73% 75% 0.0% 0 0 Exiting... (End of file Seems like the same failure, but we are falling back to one of our demuxers instead of lavf. Playing a few random videos partially fails in the same way described above. Conclusion ---------- It seems there is still a problem with newer FFmpeg versions and mplayer after having this patch applied. More investigation is needed. After this is working we still need to decide or act on the mencoder issues. As mencoder would be build by default, it would result in all non-customized builds failing. Best regards, Alexander P.S. I locally applied the vo png patch Reimar sent a while ago to avoid the compile error, I didn't test vo png yet. On 2021-04-29 22:46 +0200, Reimar Döffinger wrote:
Only for MPlayer, mencoder needs more changes. --- Makefile | 4 +- av_helpers.c | 91 +++++++++++++++++++++++++++++++++++++ av_helpers.h | 4 ++ libmpcodecs/ad_spdif.c | 4 +- libmpcodecs/vd_ffmpeg.c | 8 +++- libmpcodecs/vf.c | 2 +- libmpcodecs/vf_lavc.c | 35 +++++++------- libmpcodecs/vf_screenshot.c | 29 ++++++------ libmpdemux/demux_lavf.c | 13 ++++-- sub/av_sub.c | 14 +++--- 10 files changed, 154 insertions(+), 50 deletions(-)
diff --git a/Makefile b/Makefile index 56fb7780e..94ef50367 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,9 @@ SRCS_COMMON-$(CONFIG_VF_LAVFI) += libmpcodecs/vf_lavfi.c SRCS_COMMON-$(FFMPEG_A) += libmpcodecs/vf_fspp.c \ libmpcodecs/vf_qp.c \ libmpcodecs/vf_spp.c \ - libmpcodecs/vf_uspp.c \ + +# needs update for missing coded_frame +#libmpcodecs/vf_uspp.c \
SRCS_COMMON-$(FREETYPE) += sub/font_load_ft.c SRCS_COMMON-$(FTP) += stream/stream_ftp.c diff --git a/av_helpers.c b/av_helpers.c index 2d543b314..a4e245a19 100644 --- a/av_helpers.c +++ b/av_helpers.c @@ -20,6 +20,7 @@
#include "libavcodec/avcodec.h" #include "libavformat/avformat.h" +#include "libavutil/intreadwrite.h" #include "mp_msg.h" #include "av_helpers.h" #include "libaf/reorder_ch.h" @@ -165,3 +166,93 @@ int lavc_encode_audio(AVCodecContext *ctx, void *src, int src_len, void *dst, in } return 0; } + +#define MERGE_MARKER 0x8c4d9d108e25e9feULL + +static void bytestream_put_buffer(uint8_t **b, const uint8_t *src, unsigned int size) +{ + memcpy(*b, src, size); + *b += size; +} + +int mp_packet_merge_side_data(AVPacket *pkt){ + if(pkt->side_data_elems){ + AVBufferRef *buf; + int i; + uint8_t *p; + uint64_t size= pkt->size + 8LL + AV_INPUT_BUFFER_PADDING_SIZE; + AVPacket old= *pkt; + for (i=0; i<old.side_data_elems; i++) { + size += old.side_data[i].size + 5LL; + } + if (size > INT_MAX) + return AVERROR(EINVAL); + buf = av_buffer_alloc(size); + if (!buf) + return AVERROR(ENOMEM); + pkt->buf = buf; + pkt->data = p = buf->data; + pkt->size = size - AV_INPUT_BUFFER_PADDING_SIZE; + bytestream_put_buffer(&p, old.data, old.size); + for (i=old.side_data_elems-1; i>=0; i--) { + bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size); + AV_WB32(p, old.side_data[i].size); + p += 4; + *p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128); + } + AV_WB64(p, MERGE_MARKER); + p += 8; + memset(p, 0, AV_INPUT_BUFFER_PADDING_SIZE); + av_packet_unref(&old); + pkt->side_data_elems = 0; + pkt->side_data = NULL; + return 1; + } + return 0; +} + +int mp_packet_split_side_data(AVPacket *pkt){ + if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == MERGE_MARKER){ + int i; + unsigned int size; + uint8_t *p; + + p = pkt->data + pkt->size - 8 - 5; + for (i=1; ; i++){ + size = AV_RB32(p); + if (size>INT_MAX - 5 || p - pkt->data < size) + return 0; + if (p[4]&128) + break; + if (p - pkt->data < size + 5) + return 0; + p-= size+5; + } + + if (i > AV_PKT_DATA_NB) + return AVERROR(ERANGE); + + pkt->side_data = av_malloc_array(i, sizeof(*pkt->side_data)); + if (!pkt->side_data) + return AVERROR(ENOMEM); + + p= pkt->data + pkt->size - 8 - 5; + for (i=0; ; i++){ + size= AV_RB32(p); + pkt->side_data[i].data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); + pkt->side_data[i].size = size; + pkt->side_data[i].type = p[4]&127; + if (!pkt->side_data[i].data) + return AVERROR(ENOMEM); + memcpy(pkt->side_data[i].data, p-size, size); + pkt->size -= size + 5; + if(p[4]&128) + break; + p-= size+5; + } + pkt->size -= 8; + pkt->side_data_elems = i+1; + return 1; + } + return 0; +} diff --git a/av_helpers.h b/av_helpers.h index 9c8321305..5bef2aa63 100644 --- a/av_helpers.h +++ b/av_helpers.h @@ -22,9 +22,13 @@ #define MPLAYER_AV_HELPERS_H
struct AVCodecContext; +struct AVFrame; +struct AVPacket;
void init_avcodec(void); void init_avformat(void); int lavc_encode_audio(struct AVCodecContext *ctx, void *src, int src_len, void *dst, int dst_len); +int mp_packet_merge_side_data(struct AVPacket *pkt); +int mp_packet_split_side_data(struct AVPacket *pkt);
#endif /* MPLAYER_AV_HELPERS_H */ diff --git a/libmpcodecs/ad_spdif.c b/libmpcodecs/ad_spdif.c index 8ee472429..d49e4f51b 100644 --- a/libmpcodecs/ad_spdif.c +++ b/libmpcodecs/ad_spdif.c @@ -126,7 +126,7 @@ static int init(sh_audio_t *sh) lavf_ctx->start_time = AV_NOPTS_VALUE; for (i = 0; fmt_id_type[i].name; i++) { if (!strcmp(codec_idx2str(sh->codec->dll_idx), fmt_id_type[i].name)) { - lavf_ctx->streams[0]->codec->codec_id = fmt_id_type[i].id; + lavf_ctx->streams[0]->codecpar->codec_id = fmt_id_type[i].id; break; } } @@ -161,7 +161,7 @@ static int init(sh_audio_t *sh) } sh->ds->buffer_pos -= in_size;
- switch (lavf_ctx->streams[0]->codec->codec_id) { + switch (lavf_ctx->streams[0]->codecpar->codec_id) { case AV_CODEC_ID_AAC: spdif_ctx->iec61937_packet_size = 16384; sh->sample_format = AF_FORMAT_IEC61937_LE; diff --git a/libmpcodecs/vd_ffmpeg.c b/libmpcodecs/vd_ffmpeg.c index cb23d07b4..6e30c51f6 100644 --- a/libmpcodecs/vd_ffmpeg.c +++ b/libmpcodecs/vd_ffmpeg.c @@ -902,7 +902,7 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){ pkt.size = len; // Necessary to decode e.g. CorePNG and ZeroCodec correctly pkt.flags = (sh->ds->flags & 1) ? AV_PKT_FLAG_KEY : 0; - av_packet_split_side_data(&pkt); + mp_packet_split_side_data(&pkt); if (av_packet_get_side_data(&pkt, AV_PKT_DATA_PALETTE, NULL)) ctx->palette_sent = 1; if (!ctx->palette_sent && sh->bih && sh->bih->biBitCount <= 8) { @@ -977,6 +977,8 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){
// average MB quantizer { +// TODO: still possible in new FFmpeg API? +#if 0 int x, y; int w = ((avctx->width << lavc_param_lowres)+15) >> 4; int h = ((avctx->height << lavc_param_lowres)+15) >> 4; @@ -989,6 +991,7 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){ q += qstride; } quality /= w * h; +#endif }
all_len+=len; @@ -1079,7 +1082,8 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){ swap_palette(mpi->planes[1]); #endif /* to comfirm with newer lavc style */ - mpi->qscale = av_frame_get_qp_table(pic, &mpi->qstride, &mpi->qscale_type); +// TODO: still possible in new FFmpeg API? +// mpi->qscale = av_frame_get_qp_table(pic, &mpi->qstride, &mpi->qscale_type); mpi->pict_type=pic->pict_type; mpi->fields = MP_IMGFIELD_ORDERED; if(pic->interlaced_frame) mpi->fields |= MP_IMGFIELD_INTERLACED; diff --git a/libmpcodecs/vf.c b/libmpcodecs/vf.c index 563632cb9..f4f172a76 100644 --- a/libmpcodecs/vf.c +++ b/libmpcodecs/vf.c @@ -197,7 +197,7 @@ static const vf_info_t* const filter_list[]={ &vf_info_hue, #ifdef CONFIG_FFMPEG_A &vf_info_spp, - &vf_info_uspp, +// &vf_info_uspp, // TODO: does not currently build &vf_info_fspp, &vf_info_qp, // &vf_info_mcdeint, //TODO: vf_mcdeint is deactivated because it doesn't build after latest FFmpeg major bumps diff --git a/libmpcodecs/vf_lavc.c b/libmpcodecs/vf_lavc.c index 9acd695d7..c5252a8f0 100644 --- a/libmpcodecs/vf_lavc.c +++ b/libmpcodecs/vf_lavc.c @@ -33,12 +33,12 @@
struct vf_priv_s { - unsigned char* outbuf; - int outbuf_size; AVCodecContext* context; AVFrame* pic; - AVCodec* codec; + const AVCodec* codec; vo_mpegpes_t pes; + AVPacket *pkt; + int pkt_has_ref; };
#define lavc_venc_context (*vf->priv->context) @@ -69,10 +69,7 @@ static int config(struct vf_instance *vf, } }
- free(vf->priv->outbuf); - - vf->priv->outbuf_size=10000+width*height; // must be enough! - vf->priv->outbuf = malloc(vf->priv->outbuf_size); + if (vf->priv->pkt_has_ref) av_packet_unref(vf->priv->pkt);
if (avcodec_open2(&lavc_venc_context, vf->priv->codec, NULL) != 0) { mp_msg(MSGT_MENCODER,MSGL_ERR,MSGTR_CantOpenCodec); @@ -84,10 +81,9 @@ static int config(struct vf_instance *vf,
static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){ mp_image_t* dmpi; - int out_size; AVFrame *pic= vf->priv->pic; - int ret, got_pkt; - AVPacket pkt; + AVPacket *pkt = vf->priv->pkt; + int ret;
pic->data[0]=mpi->planes[0]; pic->data[1]=mpi->planes[1]; @@ -96,21 +92,21 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double pic->linesize[1]=mpi->stride[1]; pic->linesize[2]=mpi->stride[2];
- av_init_packet(&pkt); - pkt.data = vf->priv->outbuf; - pkt.size = vf->priv->outbuf_size; - ret = avcodec_encode_video2(&lavc_venc_context, &pkt, pic, &got_pkt); + if (vf->priv->pkt_has_ref) av_packet_unref(pkt); + ret = avcodec_send_frame(&lavc_venc_context, pic); + if (ret >= 0) { + ret = avcodec_receive_packet(&lavc_venc_context, pkt); + } + vf->priv->pkt_has_ref = ret >= 0;
- if(ret<=0) return 1; - if(!got_pkt) return 1; - out_size = pkt.size; + if(ret<0) return 1;
dmpi=vf_get_image(vf->next,IMGFMT_MPEGPES, MP_IMGTYPE_EXPORT, 0, mpi->w, mpi->h);
- vf->priv->pes.data=vf->priv->outbuf; - vf->priv->pes.size=out_size; + vf->priv->pes.data=pkt->data; + vf->priv->pes.size=pkt->size; vf->priv->pes.id=0x1E0; vf->priv->pes.timestamp=-1; // dunno
@@ -151,6 +147,7 @@ static int vf_open(vf_instance_t *vf, char *args){
vf->priv->context=avcodec_alloc_context3(vf->priv->codec); vf->priv->pic = av_frame_alloc(); + vf->priv->pkt = av_packet_alloc();
// TODO: parse args -> if(args) sscanf(args, "%d:%f", &p_quality, &p_fps); diff --git a/libmpcodecs/vf_screenshot.c b/libmpcodecs/vf_screenshot.c index 9aafac3a2..e8b87fa91 100644 --- a/libmpcodecs/vf_screenshot.c +++ b/libmpcodecs/vf_screenshot.c @@ -49,10 +49,9 @@ struct vf_priv_s { int shot, store_slices; int dw, dh; AVFrame *pic; + AVPacket *pkt; struct SwsContext *ctx; AVCodecContext *avctx; - uint8_t *outbuffer; - int outbuffer_size; };
//===========================================================================// @@ -75,7 +74,6 @@ static int config(struct vf_instance *vf, vf->priv->ctx=sws_getContextFromCmdLine(width, height, outfmt, d_width, d_height, IMGFMT_RGB24);
- av_fast_malloc(&vf->priv->outbuffer, &vf->priv->outbuffer_size, d_width * d_height * 3 * 2); if (!vf->priv->avctx) { vf->priv->avctx = avcodec_alloc_context3(NULL); vf->priv->avctx->pix_fmt = AV_PIX_FMT_RGB24; @@ -106,17 +104,21 @@ static void write_png(struct vf_priv_s *priv) { char *fname = priv->fname; FILE * fp; - AVPacket pkt; - int res, got_pkt; + AVPacket *pkt = priv->pkt; + int res;
- av_init_packet(&pkt); - pkt.data = priv->outbuffer; - pkt.size = priv->outbuffer_size; priv->pic->width = priv->avctx->width; priv->pic->height = priv->avctx->height; priv->pic->format = priv->avctx->pix_fmt; - res = avcodec_encode_video2(priv->avctx, &pkt, priv->pic, &got_pkt); - if (res < 0 || !got_pkt || pkt.size <= 0) { + res = avcodec_send_frame(priv->avctx, priv->pic); + if (res >= 0) { + res = avcodec_receive_packet(priv->avctx, pkt); + if (res == AVERROR(EAGAIN)) { + avcodec_send_frame(priv->avctx, NULL); + res = avcodec_receive_packet(priv->avctx, pkt); + } + } + if (res < 0 || pkt->size <= 0) { mp_msg(MSGT_VFILTER,MSGL_ERR,"\nFailed to encode screenshot %s!\n", fname); return; } @@ -127,7 +129,8 @@ static void write_png(struct vf_priv_s *priv) return; }
- fwrite(priv->outbuffer, pkt.size, 1, fp); + fwrite(pkt->data, pkt->size, 1, fp); + av_packet_unref(pkt);
fclose (fp); mp_msg(MSGT_VFILTER,MSGL_INFO,"*** screenshot '%s' ***\n",priv->fname); @@ -281,7 +284,7 @@ static void uninit(vf_instance_t *vf) if(vf->priv->ctx) sws_freeContext(vf->priv->ctx); av_freep(&vf->priv->pic->data[0]); av_frame_free(&vf->priv->pic); - av_freep(&vf->priv->outbuffer); + av_packet_free(&vf->priv->pkt); free(vf->priv->prefix); free(vf->priv); } @@ -298,8 +301,8 @@ static int vf_open(vf_instance_t *vf, char *args) vf->uninit=uninit; vf->priv = calloc(1, sizeof(struct vf_priv_s)); vf->priv->pic = av_frame_alloc(); + vf->priv->pkt = av_packet_alloc(); vf->priv->prefix = strdup(args ? args : "shot"); - avcodec_register_all(); if (!avcodec_find_encoder(AV_CODEC_ID_PNG)) { mp_msg(MSGT_VFILTER, MSGL_FATAL, "Could not find libavcodec PNG encoder\n"); return 0; diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c index d3e6e31ae..db18726db 100644 --- a/libmpdemux/demux_lavf.c +++ b/libmpdemux/demux_lavf.c @@ -68,7 +68,7 @@ const m_option_t lavfdopts_conf[] = { #define BIO_BUFFER_SIZE 32768
typedef struct lavf_priv { - AVInputFormat *avif; + const AVInputFormat *avif; AVFormatContext *avfc; AVIOContext *pb; int audio_streams; @@ -366,7 +366,7 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) { if (demuxer->audio->id != i) st->discard= AVDISCARD_ALL; if (priv->audio_streams == 0) { - int rg_size; + size_t rg_size; AVReplayGain *rg = (AVReplayGain*)av_stream_get_side_data(st, AV_PKT_DATA_REPLAYGAIN, &rg_size); if (rg && rg_size >= sizeof(*rg)) { priv->r_gain = rg->track_gain / 10000; @@ -420,9 +420,12 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) { if (st->time_base.den) { /* if container has time_base, use that */ sh_video->video.dwRate= st->time_base.den; sh_video->video.dwScale= st->time_base.num; +#if 0 } else { + // not available in latest FFmpeg API, ok to just remove? sh_video->video.dwRate= st->codec->time_base.den; sh_video->video.dwScale= st->codec->time_base.num; +#endif } sh_video->fps=av_q2d(st->r_frame_rate); sh_video->frametime=1/av_q2d(st->r_frame_rate); @@ -527,7 +530,7 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) { st->discard= AVDISCARD_ALL; } if (stream_type) { - AVCodec *avc = avcodec_find_decoder(codec->codec_id); + const AVCodec *avc = avcodec_find_decoder(codec->codec_id); const char *codec_name = avc ? avc->name : "unknown"; if (!avc && *stream_type == 's' && demuxer->s_streams[i]) codec_name = sh_sub_type2str(((sh_sub_t *)demuxer->s_streams[i])->type); @@ -707,7 +710,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds){ } sh = ds->sh; if (sh && sh->bih) { - int size = 0; + size_t size = 0; const uint8_t *pal = av_packet_get_side_data(&pkt, AV_PKT_DATA_PALETTE, &size); if (pal && size) memcpy(((uint8_t *)sh->bih) + sh->bih->biSize, pal, FFMIN(size, 1024)); @@ -721,7 +724,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds){ return 1; }
- av_packet_merge_side_data(&pkt); + mp_packet_merge_side_data(&pkt); dp=new_demux_packet(pkt.size); memcpy(dp->buffer, pkt.data, pkt.size);
diff --git a/sub/av_sub.c b/sub/av_sub.c index aa95202e5..fcb98a078 100644 --- a/sub/av_sub.c +++ b/sub/av_sub.c @@ -43,9 +43,9 @@ static void avsub_to_spudec(AVSubtitleRect **rects, int num_rects,
if (num_rects == 1) { spudec_set_paletted(vo_spudec, - rects[0]->pict.data[0], - rects[0]->pict.linesize[0], - rects[0]->pict.data[1], + rects[0]->data[0], + rects[0]->linesize[0], + rects[0]->data[1], rects[0]->x, rects[0]->y, rects[0]->w, @@ -66,9 +66,9 @@ static void avsub_to_spudec(AVSubtitleRect **rects, int num_rects, spudec_packet_clear(packet); for (i = 0; i < num_rects; i++) spudec_packet_fill(packet, - rects[i]->pict.data[0], - rects[i]->pict.linesize[0], - rects[i]->pict.data[1], + rects[i]->data[0], + rects[i]->linesize[0], + rects[i]->data[1], rects[i]->x - xmin, rects[i]->y - ymin, rects[i]->w, @@ -105,7 +105,7 @@ int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size, pkt.size = *size; pkt.pts = *pts * 1000; if (*pts != MP_NOPTS_VALUE && *endpts != MP_NOPTS_VALUE) - pkt.convergence_duration = (*endpts - *pts) * 1000; + pkt.duration = (*endpts - *pts) * 1000; if (!ctx) { AVCodec *sub_codec; init_avcodec(); -- 2.31.1
_______________________________________________ MPlayer-dev-eng mailing list MPlayer-dev-eng@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
Alexander
On 2021-05-01 13:04 +0200, Alexander Strasser wrote: [...]
Revision after the Major Bumps ------------------------------
commit 8b83a4a885e3b92bd09354d6cb182fca47f80973 CommitDate: Fri Apr 30 10:24:32 2021 +0200
avutil/mem: Also poison new av_realloc-allocated blocks
Now I get more than 500 checksum changes on `make fatetest`, lots of them look worrying because there are simply no decoded frames and at all.
This is probably related with failures like this:
./mplayer "$FATE_SAMPLES"/h264-conformance/MR8_BT_B.h264
MPlayer UNKNOWN-9 (C) 2000-2021 MPlayer Team
Playing /home/beastd/devel/fate/samples//h264-conformance/MR8_BT_B.h264. libavformat version 59.0.100 (internal) libavformat file format detected. [Eval @ 0x55e772033360]Undefined constant or missing '(' in 'keepside' [h264 @ 0x55e771fa0920]Unable to parse option value "keepside" [h264 @ 0x55e771fa0920]Error setting option fflags to value +keepside. LAVF_header: av_open_input_stream() failed
Exiting... (End of file)
Others are worrying because previously differently decoded frames become all the same, like in this example:
Unsure at what cost, but simply removing this av_dict_set(&opts, "fflags", "+keepside", 0); line in libmpdemux/demux_lavf.c at L608 makes the tests happy again. [...] Alexander
On Sat, May 01, 2021 at 03:34:49PM +0200, Alexander Strasser wrote:
On 2021-05-01 13:04 +0200, Alexander Strasser wrote:
Others are worrying because previously differently decoded frames become all the same, like in this example:
Unsure at what cost, but simply removing this
av_dict_set(&opts, "fflags", "+keepside", 0);
line in libmpdemux/demux_lavf.c at L608 makes the tests happy again.
I think didn't do anything ever since we added the explicit side data merging in 2016? Is that the only issue? Should I apply my patch, with that change on top then? Can disable mencoder by default, or see it it's possible to fix soonish after that. Btw. vf_screenshot would also be good to test, I admit I did not.
On 2021-05-01 17:29 +0200, Reimar Döffinger wrote:
On Sat, May 01, 2021 at 03:34:49PM +0200, Alexander Strasser wrote:
On 2021-05-01 13:04 +0200, Alexander Strasser wrote:
Others are worrying because previously differently decoded frames become all the same, like in this example:
Unsure at what cost, but simply removing this
av_dict_set(&opts, "fflags", "+keepside", 0);
line in libmpdemux/demux_lavf.c at L608 makes the tests happy again.
I think didn't do anything ever since we added the explicit side data merging in 2016? Is that the only issue? Should I apply my patch, with that change on top then?
Yeah, that would be great.
Can disable mencoder by default, or see it it's possible to fix soonish after that. Btw. vf_screenshot would also be good to test, I admit I did not.
Tested vo png and vf screenshot. Both seem to work fine. I didn't test many variations, but IMHO that shouldn't be blocker given the current situation with a broken build. Maybe you can just disable mencoder build by default for now as a short term measure. Alexander
participants (2)
-
Alexander Strasser -
Reimar Döffinger