diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 8d6dc77943..8296f818d5 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -258,7 +258,7 @@ int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, } while (bytestream2_get_byteu(&gbyte) == 255); if (size > bytestream2_get_bytes_left(&gbyte)) { - av_log(logctx, AV_LOG_ERROR, "SEI type %d size %d truncated at %d\n", + av_log(logctx, AV_LOG_WARNING, "SEI type %d size %d truncated at %d\n", type, size, bytestream2_get_bytes_left(&gbyte)); return AVERROR_INVALIDDATA; } diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c index 9bedee5f03..1c1e1417b2 100644 --- a/libavcodec/hevc_parser.c +++ b/libavcodec/hevc_parser.c @@ -85,7 +85,9 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, } if (ps->sps != ps->sps_list[ps->pps->sps_id]) { ps->sps = ps->sps_list[ps->pps->sps_id]; - ps->vps = ps->vps_list[ps->sps->vps_id]; + if (ps->vps_list && ps->vps_list[ps->sps->vps_id]) { + ps->vps = ps->vps_list[ps->sps->vps_id]; + } } ow = &ps->sps->output_window; @@ -97,7 +99,7 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, avctx->profile = ps->sps->ptl.general_ptl.profile_idc; avctx->level = ps->sps->ptl.general_ptl.level_idc; - if (ps->vps->vps_timing_info_present_flag) { + if (ps->vps && ps->vps->vps_timing_info_present_flag) { num = ps->vps->vps_num_units_in_tick; den = ps->vps->vps_time_scale; } else if (ps->sps->vui.vui_timing_info_present_flag) { diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c index fb997066d9..ad689d3030 100644 --- a/libavcodec/hevc_ps.c +++ b/libavcodec/hevc_ps.c @@ -864,9 +864,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->vps_id = get_bits(gb, 4); if (vps_list && !vps_list[sps->vps_id]) { - av_log(avctx, AV_LOG_ERROR, "VPS %d does not exist\n", - sps->vps_id); - return AVERROR_INVALIDDATA; + av_log(avctx, AV_LOG_WARNING, "VPS %d does not exist\n", sps->vps_id); } sps->max_sub_layers = get_bits(gb, 3) + 1; diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c index 855c900487..6700e7b534 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -324,7 +324,7 @@ static void export_stream_params(HEVCContext *s, const HEVCSPS *sps) { AVCodecContext *avctx = s->avctx; const HEVCParamSets *ps = &s->ps; - const HEVCVPS *vps = ps->vps_list[sps->vps_id]; + const HEVCVPS *vps = NULL; const HEVCWindow *ow = &sps->output_window; unsigned int num = 0, den = 0; @@ -364,7 +364,10 @@ static void export_stream_params(HEVCContext *s, const HEVCSPS *sps) avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; } - if (vps->vps_timing_info_present_flag) { + if (ps->vps_list && ps->vps_list[sps->vps_id]) { + vps = ps->vps_list[sps->vps_id]; + } + if (vps && vps->vps_timing_info_present_flag) { num = vps->vps_num_units_in_tick; den = vps->vps_time_scale; } else if (sps->vui.vui_timing_info_present_flag) { @@ -571,7 +574,9 @@ static int set_sps(HEVCContext *s, const HEVCSPS *sps, } s->ps.sps = sps; - s->ps.vps = s->ps.vps_list[s->ps.sps->vps_id]; + if (s->ps.vps_list && s->ps.vps_list[s->ps.sps->vps_id]) { + s->ps.vps = s->ps.vps_list[s->ps.sps->vps_id]; + } return 0; diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index ceac769c52..e4b5a4187e 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -601,23 +601,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx, if (err < 0) goto fail; - frames->initial_pool_size = 1; - // Add per-codec number of surfaces used for storing reference frames. - switch (avctx->codec_id) { - case AV_CODEC_ID_H264: - case AV_CODEC_ID_HEVC: - case AV_CODEC_ID_AV1: - frames->initial_pool_size += 16; - break; - case AV_CODEC_ID_VP9: - frames->initial_pool_size += 8; - break; - case AV_CODEC_ID_VP8: - frames->initial_pool_size += 3; - break; - default: - frames->initial_pool_size += 2; - } + frames->initial_pool_size = 0; } av_hwframe_constraints_free(&constraints); @@ -665,6 +649,8 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; VAStatus vas; int err; + AVFrame* frame; + VASurfaceID surface_id; ctx->va_config = VA_INVALID_ID; ctx->va_context = VA_INVALID_ID; @@ -683,12 +669,19 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) if (err) goto fail; + frame = av_frame_alloc(); + err = av_hwframe_get_buffer(avctx->hw_frames_ctx, frame, 0); + if (err < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to create frame: %d\n", err); + av_frame_free(&frame); + goto fail; + } + surface_id = (VASurfaceID)(uintptr_t)frame->data[3]; vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, avctx->coded_width, avctx->coded_height, - VA_PROGRESSIVE, - ctx->hwfc->surface_ids, - ctx->hwfc->nb_surfaces, + VA_PROGRESSIVE, &surface_id, 1, &ctx->va_context); + av_frame_free(&frame); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create decode " "context: %d (%s).\n", vas, vaErrorStr(vas)); diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index e146869f12..de1589fff5 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -738,6 +738,7 @@ static int vaapi_encode_get_coded_buffer_data(AVCodecContext *avctx, VABufferID buf_id, uint8_t **dst) { VAAPIEncodeContext *ctx = avctx->priv_data; + size_t len, off; VACodedBufferSegment *buf_list, *buf; VAStatus vas; int err; @@ -1544,12 +1545,14 @@ static const VAEntrypoint vaapi_encode_entrypoints_normal[] = { #endif 0 }; -#if VA_CHECK_VERSION(0, 39, 2) static const VAEntrypoint vaapi_encode_entrypoints_low_power[] = { +#if VA_CHECK_VERSION(0, 39, 2) VAEntrypointEncSliceLP, +#endif + VAEntrypointEncSlice, + VAEntrypointEncPicture, 0 }; -#endif static av_cold int vaapi_encode_profile_entrypoint(AVCodecContext *avctx) { @@ -1567,13 +1570,7 @@ static av_cold int vaapi_encode_profile_entrypoint(AVCodecContext *avctx) if (ctx->low_power) { -#if VA_CHECK_VERSION(0, 39, 2) usable_entrypoints = vaapi_encode_entrypoints_low_power; -#else - av_log(avctx, AV_LOG_ERROR, "Low-power encoding is not " - "supported with this VAAPI version.\n"); - return AVERROR(EINVAL); -#endif } else { usable_entrypoints = vaapi_encode_entrypoints_normal; } diff --git a/libavfilter/vaapi_vpp.c b/libavfilter/vaapi_vpp.c index cf2592e068..334d281f61 100644 --- a/libavfilter/vaapi_vpp.c +++ b/libavfilter/vaapi_vpp.c @@ -100,9 +100,10 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink) AVVAAPIHWConfig *hwconfig = NULL; AVHWFramesConstraints *constraints = NULL; AVHWFramesContext *output_frames; - AVVAAPIFramesContext *va_frames; VAStatus vas; int err, i; + AVFrame* frame; + VASurfaceID surface_id; if (ctx->pipeline_uninit) ctx->pipeline_uninit(avctx); @@ -199,7 +200,7 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink) output_frames->width = ctx->output_width; output_frames->height = ctx->output_height; - output_frames->initial_pool_size = 4; + output_frames->initial_pool_size = 0; err = ff_filter_init_hw_frames(avctx, outlink, 10); if (err < 0) @@ -212,14 +213,20 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink) goto fail; } - va_frames = output_frames->hwctx; - av_assert0(ctx->va_context == VA_INVALID_ID); + frame = av_frame_alloc(); + err = av_hwframe_get_buffer(outlink->hw_frames_ctx, frame, 0); + if (err < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to create frame: %d\n", err); + av_frame_free(&frame); + goto fail; + } + surface_id = (VASurfaceID)(uintptr_t)frame->data[3]; vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, ctx->output_width, ctx->output_height, - VA_PROGRESSIVE, - va_frames->surface_ids, va_frames->nb_surfaces, + VA_PROGRESSIVE, &surface_id, 1, &ctx->va_context); + av_frame_free(&frame); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create processing pipeline " "context: %d (%s).\n", vas, vaErrorStr(vas)); @@ -545,7 +552,6 @@ int ff_vaapi_vpp_init_params(AVFilterContext *avctx, *params = (VAProcPipelineParameterBuffer) { .surface = ff_vaapi_vpp_get_surface_id(input_frame), .surface_region = &ctx->input_region, - .output_region = NULL, .output_background_color = VAAPI_VPP_BACKGROUND_BLACK, .pipeline_flags = 0, .filter_flags = VA_FRAME_PICTURE, diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 774f137353..2d1f3f408f 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -727,6 +727,7 @@ static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out) if (in->colorspace == AVCOL_SPC_YCGCO) av_log(link->dst, AV_LOG_WARNING, "Detected unsupported YCgCo colorspace.\n"); + av_frame_apply_cropping(in, 0); frame_changed = in->width != link->w || in->height != link->h || in->format != link->format || @@ -762,7 +763,7 @@ static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out) scale->w && scale->h) goto scale; - if (scale->eval_mode == EVAL_MODE_INIT) { + /*if (scale->eval_mode == EVAL_MODE_INIT) { snprintf(buf, sizeof(buf) - 1, "%d", scale->w); av_opt_set(scale, "w", buf, 0); snprintf(buf, sizeof(buf) - 1, "%d", scale->h); @@ -775,7 +776,7 @@ static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out) ret = scale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr); if (ret < 0) return ret; - } + }*/ if (ctx->filter == &ff_vf_scale2ref) { scale->var_values[VAR_S2R_MAIN_N] = link->frame_count_out; @@ -804,6 +805,9 @@ FF_ENABLE_DEPRECATION_WARNINGS if ((ret = config_props(outlink)) < 0) return ret; + + link->dst->inputs[0]->w = link->w; + link->dst->inputs[0]->h = link->h; } scale: diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c index 54c055f0a9..5aa220ff40 100644 --- a/libavfilter/vf_scale_vaapi.c +++ b/libavfilter/vf_scale_vaapi.c @@ -36,6 +36,7 @@ typedef struct ScaleVAAPIContext { char *w_expr; // width expression string char *h_expr; // height expression string + int keep_ar; int force_original_aspect_ratio; int force_divisible_by; @@ -46,6 +47,8 @@ typedef struct ScaleVAAPIContext { int colour_range; char *chroma_location_string; + int enable_passthrough; + enum AVColorPrimaries colour_primaries; enum AVColorTransferCharacteristic colour_transfer; enum AVColorSpace colour_matrix; @@ -84,15 +87,19 @@ static int scale_vaapi_config_output(AVFilterLink *outlink) ff_scale_adjust_dimensions(inlink, &vpp_ctx->output_width, &vpp_ctx->output_height, ctx->force_original_aspect_ratio, ctx->force_divisible_by); - if (inlink->w == vpp_ctx->output_width && inlink->h == vpp_ctx->output_height && + if (ctx->enable_passthrough && + inlink->w == vpp_ctx->output_width && inlink->h == vpp_ctx->output_height && (vpp_ctx->input_frames->sw_format == vpp_ctx->output_format || vpp_ctx->output_format == AV_PIX_FMT_NONE) && ctx->colour_primaries == AVCOL_PRI_UNSPECIFIED && ctx->colour_transfer == AVCOL_TRC_UNSPECIFIED && ctx->colour_matrix == AVCOL_SPC_UNSPECIFIED && ctx->colour_range == AVCOL_RANGE_UNSPECIFIED && - ctx->chroma_location == AVCHROMA_LOC_UNSPECIFIED) + ctx->chroma_location == AVCHROMA_LOC_UNSPECIFIED) { vpp_ctx->passthrough = 1; + } else { + vpp_ctx->passthrough = 0; + } err = ff_vaapi_vpp_config_output(outlink); if (err < 0) @@ -114,6 +121,7 @@ static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) ScaleVAAPIContext *ctx = avctx->priv; AVFrame *output_frame = NULL; VAProcPipelineParameterBuffer params; + VARectangle output_region; int err; av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", @@ -153,6 +161,32 @@ static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) if (err < 0) goto fail; + input_frame->crop_left = 0; + input_frame->crop_right = 0; + input_frame->crop_top = 0; + input_frame->crop_bottom = 0; + if (ctx->keep_ar && fabsf((float)params.surface_region->width / params.surface_region->height - + (float)vpp_ctx->output_width / vpp_ctx->output_height) > 0.01) { + int orx = 0, ory = 0, orw = vpp_ctx->output_width, orh = vpp_ctx->output_height; + if (params.surface_region->width * vpp_ctx->output_height > + vpp_ctx->output_width * params.surface_region->height) { + // Add vertical margins. + orh = vpp_ctx->output_width * params.surface_region->height / params.surface_region->width; + ory = (vpp_ctx->output_height - orh) / 2; + } else { + // Add horizontal margins. + orw = vpp_ctx->output_height * params.surface_region->width / params.surface_region->height; + orx = (vpp_ctx->output_width - orw) / 2; + } + output_region.x = orx; + output_region.y = ory; + output_region.width = orw; + output_region.height = orh; + params.output_region = &output_region; + } else { + params.output_region = NULL; + } + params.filter_flags |= ctx->mode; err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_frame); @@ -221,6 +255,8 @@ static const AVOption scale_vaapi_options[] = { OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = FLAGS }, { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = FLAGS }, + { "keep_ar", "Keep aspect ratio by padding", + OFFSET(keep_ar), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS }, { "format", "Output video format (software format of hardware frames)", OFFSET(output_format_string), AV_OPT_TYPE_STRING, .flags = FLAGS }, { "mode", "Scaling mode", @@ -268,7 +304,7 @@ static const AVOption scale_vaapi_options[] = { { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" }, { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" }, { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS }, - + { "enable_passthrough", "Passthrough the frame args check", OFFSET(enable_passthrough), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, FLAGS }, { NULL }, }; diff --git a/libavformat/avc.c b/libavformat/avc.c index b0ceb1d2d8..ef072e3208 100644 --- a/libavformat/avc.c +++ b/libavformat/avc.c @@ -86,21 +86,23 @@ static int avc_parse_nal_units(AVIOContext *pb, NALUList *list, break; nal_end = ff_avc_find_startcode(nal_start, end); - if (pb) { - avio_wb32(pb, nal_end - nal_start); - avio_write(pb, nal_start, nal_end - nal_start); - } else if (list->nb_nalus >= nalu_limit) { - return AVERROR(ERANGE); - } else { - NALU *tmp = av_fast_realloc(list->nalus, &list->nalus_array_size, - (list->nb_nalus + 1) * sizeof(*list->nalus)); - if (!tmp) - return AVERROR(ENOMEM); - list->nalus = tmp; - tmp[list->nb_nalus++] = (NALU){ .offset = nal_start - p, - .size = nal_end - nal_start }; + if (nal_end > nal_start) { + if (pb) { + avio_wb32(pb, nal_end - nal_start); + avio_write(pb, nal_start, nal_end - nal_start); + } else if (list->nb_nalus >= nalu_limit) { + return AVERROR(ERANGE); + } else { + NALU *tmp = av_fast_realloc(list->nalus, &list->nalus_array_size, + (list->nb_nalus + 1) * sizeof(*list->nalus)); + if (!tmp) + return AVERROR(ENOMEM); + list->nalus = tmp; + tmp[list->nb_nalus++] = (NALU){ .offset = nal_start - p, + .size = nal_end - nal_start }; + } + size += 4 + nal_end - nal_start; } - size += 4 + nal_end - nal_start; nal_start = nal_end; } return size; diff --git a/libavformat/avio.c b/libavformat/avio.c index b793a7546c..383e3713c2 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -403,7 +403,7 @@ int ffurl_read2(void *urlcontext, uint8_t *buf, int size) int ffurl_read_complete(URLContext *h, unsigned char *buf, int size) { - if (!(h->flags & AVIO_FLAG_READ)) + if (!h || !(h->flags & AVIO_FLAG_READ)) return AVERROR(EIO); return retry_transfer_wrapper(h, buf, NULL, size, size, 1); } diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 32757f0514..ea70fa28ad 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -34,7 +34,7 @@ #include "url.h" #include -#define IO_BUFFER_SIZE 32768 +#define IO_BUFFER_SIZE 65536 /** * Do seeks within this distance ahead of the current buffer by skipping diff --git a/libavformat/demux.c b/libavformat/demux.c index 789e8371f8..c6e66adca2 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -636,7 +636,7 @@ FF_ENABLE_DEPRECATION_WARNINGS /* TODO: audio: time filter; video: frame reordering (pts != dts) */ if (s->use_wallclock_as_timestamps) - pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base); + pkt->dts = pkt->pts = av_rescale_q(av_gettime_relative(), AV_TIME_BASE_Q, st->time_base); if (!pktl && sti->request_probe <= 0) return 0; diff --git a/libavformat/file.c b/libavformat/file.c index cbdf48de0a..0d320c6a60 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -218,6 +218,7 @@ static int fd_dup(URLContext *h, int oldfd) static int file_close(URLContext *h) { FileContext *c = h->priv_data; + posix_fadvise(c->fd, 0, 0, POSIX_FADV_DONTNEED); int ret = close(c->fd); return (ret == -1) ? AVERROR(errno) : 0; } @@ -300,17 +301,27 @@ static int file_open(URLContext *h, const char *filename, int flags) #ifdef O_BINARY access |= O_BINARY; #endif + if (flags & AVIO_FLAG_NONBLOCK) { + access |= O_NONBLOCK; + } fd = avpriv_open(filename, access, 0666); if (fd == -1) return AVERROR(errno); + if (flags & AVIO_FLAG_NONBLOCK) { + const int rc = fcntl(fd, F_SETFL, 0); + if (rc) { + av_log(h, AV_LOG_ERROR, "Failed to remove O_NONBLOCK from '%s': %d\n", filename, rc); + } + } c->fd = fd; h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode); /* Buffer writes more than the default 32k to improve throughput especially * with networked file systems */ - if (!h->is_streamed && flags & AVIO_FLAG_WRITE) - h->min_packet_size = h->max_packet_size = 262144; + if (!h->is_streamed && (flags & AVIO_FLAG_WRITE) && !(flags & AVIO_FLAG_DIRECT)) { + h->min_packet_size = 262144; + } if (c->seekable >= 0) h->is_streamed = !c->seekable; diff --git a/libavformat/hevc.c b/libavformat/hevc.c index ca5187a92e..ff5b36c986 100644 --- a/libavformat/hevc.c +++ b/libavformat/hevc.c @@ -867,7 +867,7 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) vps_count = hvcc->arrays[VPS_INDEX].numNalus; sps_count = hvcc->arrays[SPS_INDEX].numNalus; pps_count = hvcc->arrays[PPS_INDEX].numNalus; - if (!vps_count || vps_count > HEVC_MAX_VPS_COUNT || + if (vps_count > HEVC_MAX_VPS_COUNT || !sps_count || sps_count > HEVC_MAX_SPS_COUNT || !pps_count || pps_count > HEVC_MAX_PPS_COUNT) return AVERROR_INVALIDDATA; @@ -1059,8 +1059,10 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, } ret = ff_avc_parse_nal_units_buf(data, &start, &size); - if (ret < 0) + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "ff_avc_parse_nal_units_buf failed with %d\n", ret); return ret; + } hvcc_init(&hvcc); @@ -1081,8 +1083,10 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, if (type == array_idx_to_type[i]) { ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, &hvcc, i); - if (ret < 0) + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "hvcc_add_nal_unit failed with %d\n", ret); goto end; + } break; } } diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index da18ffc60c..2e56b37c85 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -630,11 +630,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, previous_segment = segment; segment = previous_segment->next; segment_cnt++; - if (playlist_duration <= -previous_segment->duration) { - previous_segment->next = NULL; - break; - } - if (segment_cnt >= hls->hls_delete_threshold) { + if (playlist_duration <= -previous_segment->duration && segment_cnt >= hls->hls_delete_threshold) { previous_segment->next = NULL; break; } @@ -2091,6 +2087,12 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) } else if (av_strstart(keyval, "ccgroup:", &val)) { vs->ccgroup = val; continue; + } else if (av_strstart(keyval, "sgroup:", &val)) { + av_free(vs->sgroup); + vs->sgroup = av_strdup(val); + if (!vs->sgroup) + return AVERROR(ENOMEM); + continue; } else if (av_strstart(keyval, "v:", &val)) { codec_type = AVMEDIA_TYPE_VIDEO; hls->has_video_m3u8 = 1; diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c index 9780928357..104eacd45a 100644 --- a/libavformat/httpauth.c +++ b/libavformat/httpauth.c @@ -99,7 +99,10 @@ void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, ff_parse_key_value(p, (ff_parse_key_val_cb) handle_basic_params, state); } else if (av_stristart(value, "Digest ", &p) && - state->auth_type <= HTTP_AUTH_DIGEST) { + state->auth_type <= HTTP_AUTH_DIGEST && + // Only MD5 is supported now. + (state->digest_params.algorithm[0] == 0 || + strcmp(state->digest_params.algorithm, "MD5") != 0)) { state->auth_type = HTTP_AUTH_DIGEST; memset(&state->digest_params, 0, sizeof(DigestParams)); state->realm[0] = 0; diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index fab7e2cd4f..7337a99f97 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -4258,10 +4258,10 @@ static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt) } while (matroska_deliver_packet(matroska, pkt)) { - if (matroska->done) - return (ret < 0) ? ret : AVERROR_EOF; if (matroska_parse_cluster(matroska) < 0 && !matroska->done) ret = matroska_resync(matroska, matroska->resync_pos); + if (matroska->done) + return (ret < 0) ? ret : AVERROR_EOF; } return 0; diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 1457a6890c..a2061dacb2 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -1133,8 +1133,9 @@ static int mkv_assemble_native_codecprivate(AVFormatContext *s, AVIOContext *dyn case AV_CODEC_ID_WAVPACK: return put_wv_codecpriv(dyn_cp, extradata, extradata_size); case AV_CODEC_ID_H264: - return ff_isom_write_avcc(dyn_cp, extradata, - extradata_size); + ff_isom_write_avcc(dyn_cp, extradata, + extradata_size); + return 0; case AV_CODEC_ID_HEVC: return ff_isom_write_hvcc(dyn_cp, extradata, extradata_size, 0); diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 1b50e8df87..8e875019cf 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -6072,8 +6072,8 @@ static int check_pkt(AVFormatContext *s, AVPacket *pkt) duration = pkt->dts - ref; if (pkt->dts < ref || duration >= INT_MAX) { - av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" is out of range\n", - duration, pkt->dts); + av_log(s, AV_LOG_WARNING, "%p Application provided duration: %"PRId64" / timestamp: %"PRId64" is out of range for mov/mp4 format\n", + s, duration, pkt->dts); pkt->dts = ref + 1; pkt->pts = AV_NOPTS_VALUE; @@ -6581,38 +6581,6 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) if (!pkt->size) return mov_write_single_packet(s, pkt); /* Passthrough. */ - /* - * Subtitles require special handling. - * - * 1) For full complaince, every track must have a sample at - * dts == 0, which is rarely true for subtitles. So, as soon - * as we see any packet with dts > 0, write an empty subtitle - * at dts == 0 for any subtitle track with no samples in it. - * - * 2) For each subtitle track, check if the current packet's - * dts is past the duration of the last subtitle sample. If - * so, we now need to write an end sample for that subtitle. - * - * This must be done conditionally to allow for subtitles that - * immediately replace each other, in which case an end sample - * is not needed, and is, in fact, actively harmful. - * - * 3) See mov_write_trailer for how the final end sample is - * handled. - */ - for (i = 0; i < mov->nb_streams; i++) { - MOVTrack *trk = &mov->tracks[i]; - int ret; - - if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT && - trk->track_duration < pkt->dts && - (trk->entry == 0 || !trk->last_sample_is_subtitle_end)) { - ret = mov_write_subtitle_end_packet(s, i, trk->track_duration); - if (ret < 0) return ret; - trk->last_sample_is_subtitle_end = 1; - } - } - if (trk->squash_fragment_samples_to_one) { /* * If the track has to have its samples squashed into one sample, @@ -7655,7 +7623,7 @@ static int mov_write_trailer(AVFormatContext *s) MOVTrack *trk = &mov->tracks[i]; if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT && !trk->last_sample_is_subtitle_end) { - mov_write_subtitle_end_packet(s, i, trk->track_duration); + mov_write_subtitle_end_packet(s, i, trk->start_dts + trk->track_duration); trk->last_sample_is_subtitle_end = 1; } } diff --git a/libavformat/mpjpegdec.c b/libavformat/mpjpegdec.c index 236aed716a..77a716bcac 100644 --- a/libavformat/mpjpegdec.c +++ b/libavformat/mpjpegdec.c @@ -19,6 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE +#include + #include "libavutil/avstring.h" #include "libavutil/opt.h" @@ -282,6 +285,23 @@ static char* mpjpeg_get_boundary(AVIOContext* pb) return res; } +static int shrink_buffer(AVIOContext *pb) { + const int data_len = pb->buf_end - pb->buf_ptr; + uint8_t *orig_buffer = pb->buffer; + uint8_t *new_buffer = NULL; + + new_buffer = av_malloc(data_len); + if (!new_buffer) return AVERROR(ENOMEM); + memcpy(new_buffer, pb->buf_ptr, data_len); + + pb->buffer = pb->buf_ptr = new_buffer; + pb->buffer_size = data_len; + pb->buf_end = pb->buffer + data_len; + + av_free(orig_buffer); + return 0; +} + static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) { int size; @@ -317,33 +337,39 @@ static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) /* size has been provided to us in MIME header */ ret = av_get_packet(s->pb, pkt, size); } else { - /* no size was given -- we read until the next boundary or end-of-file */ - int len; + int remaining = 0; - const int read_chunk = 2048; + // Use a large read chunk to avoid wasteful recopies as the buffer grows. This should + // be enough to hold an average VGA frame. + const int read_chunk = 128 * 1024; + const int seekable = s->pb->seekable; pkt->pos = avio_tell(s->pb); + // Some server might not support seek. Disable seek to make sure it always works. + s->pb->seekable = 0; while ((ret = ffio_ensure_seekback(s->pb, read_chunk)) >= 0 && /* we may need to return as much as all we've read back to the buffer */ (ret = av_append_packet(s->pb, pkt, read_chunk)) >= 0) { - /* scan the new data */ - char *start; - - len = ret; - start = pkt->data + pkt->size - len; - do { - if (!memcmp(start, mpjpeg->searchstr, mpjpeg->searchstr_len)) { - // got the boundary! rewind the stream - avio_seek(s->pb, -len, SEEK_CUR); - pkt->size -= len; - return pkt->size; - } - len--; - start++; - } while (len >= mpjpeg->searchstr_len); - avio_seek(s->pb, -len, SEEK_CUR); - pkt->size -= len; + int len = ret + remaining; + uint8_t* end = memmem(pkt->data + pkt->size - len, len, mpjpeg->searchstr, + mpjpeg->searchstr_len); + if (end) { + int rc; + len = pkt->data + pkt->size - end; + // got the boundary! rewind the stream + rc = avio_seek(s->pb, -len, SEEK_CUR); + if (rc < 0) + av_log(s, AV_LOG_ERROR, "rc = %d(%s), len = %d\n", rc, av_err2str(rc), len); + // ffio_ensure_seekback always adds at least an extra packet worth of space + // beyond what is requested, so a read after using it will never allow the + // buffer to shrink. Shrink it now to prevent unbounded growth. + shrink_buffer(s->pb); + pkt->size -= len; + return pkt->size; + } + remaining = mpjpeg->searchstr_len - 1; } + s->pb->seekable = seekable; /* error or EOF occurred */ if (ret == AVERROR_EOF) { diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c index 3d444ccbfd..e1501d52e6 100644 --- a/libavformat/rtspenc.c +++ b/libavformat/rtspenc.c @@ -253,6 +253,6 @@ const FFOutputFormat ff_rtsp_muxer = { .write_header = rtsp_write_header, .write_packet = rtsp_write_packet, .write_trailer = rtsp_write_close, - .p.flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER, + .p.flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT, .p.priv_class = &rtsp_muxer_class, }; diff --git a/libavformat/sdp.c b/libavformat/sdp.c index 69e285afe6..d8276688b1 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -298,7 +298,7 @@ static int extradata2psets_hevc(const AVCodecParameters *par, char **out) pos += len; } } - if (!ps_pos[0] || !ps_pos[1] || !ps_pos[2]) + if (!ps_pos[1] || !ps_pos[2]) goto err; psets = av_mallocz(MAX_PSET_SIZE); @@ -309,11 +309,16 @@ static int extradata2psets_hevc(const AVCodecParameters *par, char **out) psets[0] = '\0'; + int first = 1; for (i = 0; i < 3; i++) { pos = ps_pos[i]; + if (!pos) continue; - if (i > 0) + if (first) { + first = 0; + } else { av_strlcat(psets, "; ", MAX_PSET_SIZE); + } av_strlcatf(psets, MAX_PSET_SIZE, "sprop-%s=", ps_names[i]); // Skipping boundary checks in the input here; we've already traversed diff --git a/libavformat/udp.c b/libavformat/udp.c index d9514f5026..3e96b95bba 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -73,9 +73,9 @@ #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif -#define UDP_TX_BUF_SIZE 32768 -#define UDP_RX_BUF_SIZE 393216 -#define UDP_MAX_PKT_SIZE 65536 +#define UDP_TX_BUF_SIZE 1048576 +#define UDP_RX_BUF_SIZE 1048576 +#define UDP_MAX_PKT_SIZE 425984 #define UDP_HEADER_SIZE 8 typedef struct UDPContext { diff --git a/libavformat/webvttenc.c b/libavformat/webvttenc.c index 1337045325..7027853d86 100644 --- a/libavformat/webvttenc.c +++ b/libavformat/webvttenc.c @@ -58,6 +58,7 @@ static int webvtt_write_header(AVFormatContext *ctx) avpriv_set_pts_info(s, 64, 1, 1000); avio_printf(pb, "WEBVTT\n"); + avio_printf(pb, "X-TIMESTAMP-MAP=MPEGTS:0,LOCAL:00:00:00.000\n"); return 0; } diff --git a/libavutil/buffer.c b/libavutil/buffer.c index a8101d83f0..88641f2ac8 100644 --- a/libavutil/buffer.c +++ b/libavutil/buffer.c @@ -269,6 +269,8 @@ AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque, return NULL; } + pool->free_list_size = 3; + pool->num_entries = 0; pool->size = size; pool->opaque = opaque; pool->alloc2 = alloc; @@ -291,6 +293,8 @@ AVBufferPool *av_buffer_pool_init(size_t size, AVBufferRef* (*alloc)(size_t size return NULL; } + pool->free_list_size = 3; + pool->num_entries = 0; pool->size = size; pool->alloc = alloc ? alloc : av_buffer_alloc; @@ -347,10 +351,16 @@ static void pool_release_buffer(void *opaque, uint8_t *data) BufferPoolEntry *buf = opaque; AVBufferPool *pool = buf->pool; - ff_mutex_lock(&pool->mutex); - buf->next = pool->pool; - pool->pool = buf; - ff_mutex_unlock(&pool->mutex); + if (pool->num_entries >= pool->free_list_size) { + buf->free(buf->opaque, buf->data); + av_freep(&buf); + } else { + ff_mutex_lock(&pool->mutex); + buf->next = pool->pool; + pool->pool = buf; + pool->num_entries++; + ff_mutex_unlock(&pool->mutex); + } if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1) buffer_pool_free(pool); @@ -399,6 +409,7 @@ AVBufferRef *av_buffer_pool_get(AVBufferPool *pool) ret = buffer_create(&buf->buffer, buf->data, pool->size, pool_release_buffer, buf, 0); if (ret) { + pool->num_entries--; pool->pool = buf->next; buf->next = NULL; buf->buffer.flags_internal |= BUFFER_FLAG_NO_FREE; @@ -420,3 +431,7 @@ void *av_buffer_pool_buffer_get_opaque(const AVBufferRef *ref) av_assert0(buf); return buf->opaque; } + +void av_buffer_pool_set_free_list_size(AVBufferPool *pool, int free_list_size) { + pool->free_list_size = free_list_size; +} diff --git a/libavutil/buffer.h b/libavutil/buffer.h index e1ef5b7f07..016e5fdb34 100644 --- a/libavutil/buffer.h +++ b/libavutil/buffer.h @@ -284,6 +284,8 @@ AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef* (*alloc)(void *opaque, size_t size), void (*pool_free)(void *opaque)); +void av_buffer_pool_set_free_list_size(AVBufferPool *pool, int free_list_size); + /** * Mark the pool as being available for freeing. It will actually be freed only * once all the allocated buffers associated with the pool are released. Thus it diff --git a/libavutil/buffer_internal.h b/libavutil/buffer_internal.h index adb916aaa2..43ba2f6be4 100644 --- a/libavutil/buffer_internal.h +++ b/libavutil/buffer_internal.h @@ -88,6 +88,8 @@ typedef struct BufferPoolEntry { struct AVBufferPool { AVMutex mutex; BufferPoolEntry *pool; + int free_list_size; + int num_entries; /* * This is used to track when the pool is to be freed. diff --git a/libavutil/frame.c b/libavutil/frame.c index 6f4e6ea570..e2c1673a88 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -152,7 +152,7 @@ static int get_video_buffer(AVFrame *frame, int align) total_size += sizes[i]; } - frame->buf[0] = av_buffer_alloc(total_size); + frame->buf[0] = av_buffer_allocz(total_size); if (!frame->buf[0]) { ret = AVERROR(ENOMEM); goto fail; @@ -221,7 +221,7 @@ FF_ENABLE_DEPRECATION_WARNINGS frame->extended_data = frame->data; for (int i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) { - frame->buf[i] = av_buffer_alloc(frame->linesize[0]); + frame->buf[i] = av_buffer_allocz(frame->linesize[0]); if (!frame->buf[i]) { av_frame_unref(frame); return AVERROR(ENOMEM); @@ -229,7 +229,7 @@ FF_ENABLE_DEPRECATION_WARNINGS frame->extended_data[i] = frame->data[i] = frame->buf[i]->data; } for (int i = 0; i < planes - AV_NUM_DATA_POINTERS; i++) { - frame->extended_buf[i] = av_buffer_alloc(frame->linesize[0]); + frame->extended_buf[i] = av_buffer_allocz(frame->linesize[0]); if (!frame->extended_buf[i]) { av_frame_unref(frame); return AVERROR(ENOMEM); @@ -814,7 +814,7 @@ AVFrameSideData *av_frame_new_side_data(AVFrame *frame, size_t size) { AVFrameSideData *ret; - AVBufferRef *buf = av_buffer_alloc(size); + AVBufferRef *buf = av_buffer_allocz(size); ret = av_frame_new_side_data_from_buf(frame, type, buf); if (!ret) av_buffer_unref(&buf); diff --git a/libavutil/log.c b/libavutil/log.c index 5948e50467..3cccd4c0f1 100644 --- a/libavutil/log.c +++ b/libavutil/log.c @@ -43,6 +43,14 @@ #include "log.h" #include "thread.h" +#if CONFIG_LIBMFX +#include +#endif + +#if CONFIG_VAAPI +#include +#endif + static AVMutex mutex = AV_MUTEX_INITIALIZER; #define LINE_SZ 1024 @@ -442,6 +450,22 @@ int av_log_get_level(void) void av_log_set_level(int level) { av_log_level = level; +#if CONFIG_LIBMFX + if (level >= AV_LOG_VERBOSE) { + g_libmfx_log_level = DL_LOADED_LIBRARY; + } else if (level >= AV_LOG_INFO) { + g_libmfx_log_level = DL_INFO; + } else if (level >= AV_LOG_WARNING) { + g_libmfx_log_level = DL_WRN; + } else if (level >= AV_LOG_ERROR) { + g_libmfx_log_level = DL_ERROR; + } else { + g_libmfx_log_level = DL_NONE; + } +#endif +#if CONFIG_VAAPI + g_va_log_level = level; +#endif } void av_log_set_flags(int arg) diff --git a/libswscale/utils.c b/libswscale/utils.c index d50b437a62..81464e6934 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -2056,7 +2056,7 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, c->dstRange |= handle_jpeg(&c->dstFormat); if (src_format != c->srcFormat || dst_format != c->dstFormat) - av_log(c, AV_LOG_WARNING, "deprecated pixel format used, make sure you did set range correctly\n"); + av_log(c, AV_LOG_INFO, "deprecated pixel format used, make sure you did set range correctly\n"); if (c->nb_threads != 1) { ret = context_init_threaded(c, srcFilter, dstFilter); diff --git a/libswscale/yuv2rgb.c b/libswscale/yuv2rgb.c index 26282d1ef1..13708203fc 100644 --- a/libswscale/yuv2rgb.c +++ b/libswscale/yuv2rgb.c @@ -690,7 +690,7 @@ SwsFunc ff_yuv2rgb_get_func_ptr(SwsContext *c) if (t) return t; - av_log(c, AV_LOG_WARNING, + av_log(c, AV_LOG_INFO, "No accelerated colorspace conversion found from %s to %s.\n", av_get_pix_fmt_name(c->srcFormat), av_get_pix_fmt_name(c->dstFormat));