X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Futils.c;h=c1f8e2294863a084cc2daf48eada4d4cf219a9aa;hb=6bc5ef37cbf6628dd4f4c9dae9d8b3009fc81408;hp=216e5439ea50117c3d25cab5a978eb5fdca703df;hpb=2ef37691a0597529280dcb5be90325687eadac26;p=ffmpeg diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 216e5439ea5..c1f8e229486 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -656,8 +656,8 @@ static int video_get_buffer(AVCodecContext *s, AVFrame *pic) const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format); int i; - if (pic->data[0]) { - av_log(s, AV_LOG_ERROR, "pic->data[0]!=NULL in avcodec_default_get_buffer\n"); + if (pic->data[0] || pic->data[1] || pic->data[2] || pic->data[3]) { + av_log(s, AV_LOG_ERROR, "pic->data[*]!=NULL in avcodec_default_get_buffer\n"); return -1; } @@ -757,10 +757,11 @@ int ff_init_buffer_info(AVCodecContext *avctx, AVFrame *frame) enum AVPacketSideDataType packet; enum AVFrameSideDataType frame; } sd[] = { - { AV_PKT_DATA_REPLAYGAIN , AV_FRAME_DATA_REPLAYGAIN }, - { AV_PKT_DATA_DISPLAYMATRIX, AV_FRAME_DATA_DISPLAYMATRIX }, - { AV_PKT_DATA_STEREO3D, AV_FRAME_DATA_STEREO3D }, - { AV_PKT_DATA_AUDIO_SERVICE_TYPE, AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, + { AV_PKT_DATA_REPLAYGAIN , AV_FRAME_DATA_REPLAYGAIN }, + { AV_PKT_DATA_DISPLAYMATRIX, AV_FRAME_DATA_DISPLAYMATRIX }, + { AV_PKT_DATA_STEREO3D, AV_FRAME_DATA_STEREO3D }, + { AV_PKT_DATA_AUDIO_SERVICE_TYPE, AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, + { AV_PKT_DATA_MASTERING_DISPLAY_METADATA, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA }, }; if (pkt) { @@ -852,6 +853,30 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame) return ff_init_buffer_info(avctx, frame); } +static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame) +{ + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + int i; + int num_planes = av_pix_fmt_count_planes(frame->format); + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int flags = desc ? desc->flags : 0; + if (num_planes == 1 && (flags & AV_PIX_FMT_FLAG_PAL)) + num_planes = 2; + for (i = 0; i < num_planes; i++) { + av_assert0(frame->data[i]); + } + // For now do not enforce anything for palette of pseudopal formats + if (num_planes == 1 && (flags & AV_PIX_FMT_FLAG_PSEUDOPAL)) + num_planes = 2; + // For formats without data like hwaccel allow unused pointers to be non-NULL. + for (i = num_planes; num_planes > 0 && i < FF_ARRAY_ELEMS(frame->data); i++) { + if (frame->data[i]) + av_log(avctx, AV_LOG_ERROR, "Buffer returned by get_buffer2() did not zero unused plane pointers\n"); + frame->data[i] = NULL; + } + } +} + static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) { const AVHWAccel *hwaccel = avctx->hwaccel; @@ -863,13 +888,17 @@ static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) av_log(avctx, AV_LOG_ERROR, "video_get_buffer: image parameters invalid\n"); return AVERROR(EINVAL); } - } - if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + if (frame->width <= 0 || frame->height <= 0) { frame->width = FFMAX(avctx->width, AV_CEIL_RSHIFT(avctx->coded_width, avctx->lowres)); frame->height = FFMAX(avctx->height, AV_CEIL_RSHIFT(avctx->coded_height, avctx->lowres)); override_dimensions = 0; } + + if (frame->data[0] || frame->data[1] || frame->data[2] || frame->data[3]) { + av_log(avctx, AV_LOG_ERROR, "pic->data[*]!=NULL in get_buffer_internal\n"); + return AVERROR(EINVAL); + } } ret = ff_decode_frame_props(avctx, frame); if (ret < 0) @@ -884,6 +913,8 @@ static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) avctx->sw_pix_fmt = avctx->pix_fmt; ret = avctx->get_buffer2(avctx, frame, flags); + if (ret >= 0) + validate_avframe_allocation(avctx, frame); end: if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions) { @@ -2001,7 +2032,8 @@ static int apply_param_change(AVCodecContext *avctx, AVPacket *avpkt) if (!(avctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE)) { av_log(avctx, AV_LOG_ERROR, "This decoder does not support parameter " "changes, but PARAM_CHANGE side data was sent to it.\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail2; } if (size < 4) @@ -2016,7 +2048,8 @@ static int apply_param_change(AVCodecContext *avctx, AVPacket *avpkt) val = bytestream_get_le32(&data); if (val <= 0 || val > INT_MAX) { av_log(avctx, AV_LOG_ERROR, "Invalid channel count"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail2; } avctx->channels = val; size -= 4; @@ -2033,7 +2066,8 @@ static int apply_param_change(AVCodecContext *avctx, AVPacket *avpkt) val = bytestream_get_le32(&data); if (val <= 0 || val > INT_MAX) { av_log(avctx, AV_LOG_ERROR, "Invalid sample rate"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail2; } avctx->sample_rate = val; size -= 4; @@ -2046,13 +2080,20 @@ static int apply_param_change(AVCodecContext *avctx, AVPacket *avpkt) size -= 8; ret = ff_set_dimensions(avctx, avctx->width, avctx->height); if (ret < 0) - return ret; + goto fail2; } return 0; fail: av_log(avctx, AV_LOG_ERROR, "PARAM_CHANGE side data too small.\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; +fail2: + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n"); + if (avctx->err_recognition & AV_EF_EXPLODE) + return ret; + } + return 0; } static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame) @@ -2127,11 +2168,8 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi (avctx->active_thread_type & FF_THREAD_FRAME)) { int did_split = av_packet_split_side_data(&tmp); ret = apply_param_change(avctx, &tmp); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n"); - if (avctx->err_recognition & AV_EF_EXPLODE) - goto fail; - } + if (ret < 0) + goto fail; avctx->internal->pkt = &tmp; if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) @@ -2228,11 +2266,8 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx, AVPacket tmp = *avpkt; int did_split = av_packet_split_side_data(&tmp); ret = apply_param_change(avctx, &tmp); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n"); - if (avctx->err_recognition & AV_EF_EXPLODE) - goto fail; - } + if (ret < 0) + goto fail; avctx->internal->pkt = &tmp; if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) @@ -2306,8 +2341,7 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx, int64_t diff_ts = av_rescale_q(frame->nb_samples - discard_padding, (AVRational){1, avctx->sample_rate}, avctx->pkt_timebase); - if (av_frame_get_pkt_duration(frame) >= diff_ts) - av_frame_set_pkt_duration(frame, av_frame_get_pkt_duration(frame) - diff_ts); + av_frame_set_pkt_duration(frame, diff_ts); } else { av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for discarded samples.\n"); } @@ -2426,6 +2460,79 @@ static int utf8_check(const uint8_t *str) return 1; } +#if FF_API_ASS_TIMING +static void insert_ts(AVBPrint *buf, int ts) +{ + if (ts == -1) { + av_bprintf(buf, "9:59:59.99,"); + } else { + int h, m, s; + + h = ts/360000; ts -= 360000*h; + m = ts/ 6000; ts -= 6000*m; + s = ts/ 100; ts -= 100*s; + av_bprintf(buf, "%d:%02d:%02d.%02d,", h, m, s, ts); + } +} + +static int convert_sub_to_old_ass_form(AVSubtitle *sub, const AVPacket *pkt, AVRational tb) +{ + int i; + AVBPrint buf; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + for (i = 0; i < sub->num_rects; i++) { + char *final_dialog; + const char *dialog; + AVSubtitleRect *rect = sub->rects[i]; + int ts_start, ts_duration = -1; + long int layer; + + if (rect->type != SUBTITLE_ASS || !strncmp(rect->ass, "Dialogue: ", 10)) + continue; + + av_bprint_clear(&buf); + + /* skip ReadOrder */ + dialog = strchr(rect->ass, ','); + if (!dialog) + continue; + dialog++; + + /* extract Layer or Marked */ + layer = strtol(dialog, (char**)&dialog, 10); + if (*dialog != ',') + continue; + dialog++; + + /* rescale timing to ASS time base (ms) */ + ts_start = av_rescale_q(pkt->pts, tb, av_make_q(1, 100)); + if (pkt->duration != -1) + ts_duration = av_rescale_q(pkt->duration, tb, av_make_q(1, 100)); + sub->end_display_time = FFMAX(sub->end_display_time, 10 * ts_duration); + + /* construct ASS (standalone file form with timestamps) string */ + av_bprintf(&buf, "Dialogue: %ld,", layer); + insert_ts(&buf, ts_start); + insert_ts(&buf, ts_duration == -1 ? -1 : ts_start + ts_duration); + av_bprintf(&buf, "%s\r\n", dialog); + + final_dialog = av_strdup(buf.str); + if (!av_bprint_is_complete(&buf) || !final_dialog) { + av_freep(&final_dialog); + av_bprint_finalize(&buf, NULL); + return AVERROR(ENOMEM); + } + av_freep(&rect->ass); + rect->ass = final_dialog; + } + + av_bprint_finalize(&buf, NULL); + return 0; +} +#endif + int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt) @@ -2476,6 +2583,15 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, av_assert1((ret >= 0) >= !!*got_sub_ptr && !!*got_sub_ptr >= !!sub->num_rects); +#if FF_API_ASS_TIMING + if (avctx->sub_text_format == FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS + && *got_sub_ptr && sub->num_rects) { + const AVRational tb = avctx->pkt_timebase.num ? avctx->pkt_timebase + : avctx->time_base; + ret = convert_sub_to_old_ass_form(sub, avpkt, tb); + } +#endif + if (sub->num_rects && !sub->end_display_time && avpkt->duration && avctx->pkt_timebase.num) { AVRational ms = { 1, 1000 }; @@ -3036,21 +3152,16 @@ int av_get_bits_per_sample(enum AVCodecID codec_id) } } -int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) +static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, + uint32_t tag, int bits_per_coded_sample, int64_t bitrate, + uint8_t * extradata, int frame_size, int frame_bytes) { - int id, sr, ch, ba, tag, bps; - - id = avctx->codec_id; - sr = avctx->sample_rate; - ch = avctx->channels; - ba = avctx->block_align; - tag = avctx->codec_tag; - bps = av_get_exact_bits_per_sample(avctx->codec_id); + int bps = av_get_exact_bits_per_sample(id); /* codecs with an exact constant bits per sample */ if (bps > 0 && ch > 0 && frame_bytes > 0 && ch < 32768 && bps < 32768) return (frame_bytes * 8LL) / (bps * ch); - bps = avctx->bits_per_coded_sample; + bps = bits_per_coded_sample; /* codecs with a fixed packet duration */ switch (id) { @@ -3128,6 +3239,7 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) case AV_CODEC_ID_ADPCM_DTK: return frame_bytes / (16 * ch) * 28; case AV_CODEC_ID_ADPCM_4XM: + case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_IMA_ISS: return (frame_bytes - 4 * ch) * 2 / ch; case AV_CODEC_ID_ADPCM_IMA_SMJPEG: @@ -3136,7 +3248,7 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) return (frame_bytes - 8) * 2 / ch; case AV_CODEC_ID_ADPCM_THP: case AV_CODEC_ID_ADPCM_THP_LE: - if (avctx->extradata) + if (extradata) return frame_bytes * 14 / (8 * ch); break; case AV_CODEC_ID_ADPCM_XA: @@ -3171,7 +3283,7 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) if (ba > 0) { /* calc from frame_bytes, channels, and block_align */ int blocks = frame_bytes / ba; - switch (avctx->codec_id) { + switch (id) { case AV_CODEC_ID_ADPCM_IMA_WAV: if (bps < 2 || bps > 5) return 0; @@ -3189,7 +3301,7 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) if (bps > 0) { /* calc from frame_bytes, channels, and bits_per_coded_sample */ - switch (avctx->codec_id) { + switch (id) { case AV_CODEC_ID_PCM_DVD: if(bps<4) return 0; @@ -3206,19 +3318,37 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) } /* Fall back on using frame_size */ - if (avctx->frame_size > 1 && frame_bytes) - return avctx->frame_size; + if (frame_size > 1 && frame_bytes) + return frame_size; //For WMA we currently have no other means to calculate duration thus we //do it here by assuming CBR, which is true for all known cases. - if (avctx->bit_rate>0 && frame_bytes>0 && avctx->sample_rate>0 && avctx->block_align>1) { - if (avctx->codec_id == AV_CODEC_ID_WMAV1 || avctx->codec_id == AV_CODEC_ID_WMAV2) - return (frame_bytes * 8LL * avctx->sample_rate) / avctx->bit_rate; + if (bitrate > 0 && frame_bytes > 0 && sr > 0 && ba > 1) { + if (id == AV_CODEC_ID_WMAV1 || id == AV_CODEC_ID_WMAV2) + return (frame_bytes * 8LL * sr) / bitrate; } return 0; } +int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) +{ + return get_audio_frame_duration(avctx->codec_id, avctx->sample_rate, + avctx->channels, avctx->block_align, + avctx->codec_tag, avctx->bits_per_coded_sample, + avctx->bit_rate, avctx->extradata, avctx->frame_size, + frame_bytes); +} + +int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes) +{ + return get_audio_frame_duration(par->codec_id, par->sample_rate, + par->channels, par->block_align, + par->codec_tag, par->bits_per_coded_sample, + par->bit_rate, par->extradata, par->frame_size, + frame_bytes); +} + #if !HAVE_THREADS int ff_thread_init(AVCodecContext *s) { @@ -3570,3 +3700,191 @@ AVCPBProperties *ff_add_cpb_side_data(AVCodecContext *avctx) return props; } + +static void codec_parameters_reset(AVCodecParameters *par) +{ + av_freep(&par->extradata); + + memset(par, 0, sizeof(*par)); + + par->codec_type = AVMEDIA_TYPE_UNKNOWN; + par->codec_id = AV_CODEC_ID_NONE; + par->format = -1; + par->field_order = AV_FIELD_UNKNOWN; + par->color_range = AVCOL_RANGE_UNSPECIFIED; + par->color_primaries = AVCOL_PRI_UNSPECIFIED; + par->color_trc = AVCOL_TRC_UNSPECIFIED; + par->color_space = AVCOL_SPC_UNSPECIFIED; + par->chroma_location = AVCHROMA_LOC_UNSPECIFIED; + par->sample_aspect_ratio = (AVRational){ 0, 1 }; + par->profile = FF_PROFILE_UNKNOWN; + par->level = FF_LEVEL_UNKNOWN; +} + +AVCodecParameters *avcodec_parameters_alloc(void) +{ + AVCodecParameters *par = av_mallocz(sizeof(*par)); + + if (!par) + return NULL; + codec_parameters_reset(par); + return par; +} + +void avcodec_parameters_free(AVCodecParameters **ppar) +{ + AVCodecParameters *par = *ppar; + + if (!par) + return; + codec_parameters_reset(par); + + av_freep(ppar); +} + +int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src) +{ + codec_parameters_reset(dst); + memcpy(dst, src, sizeof(*dst)); + + dst->extradata = NULL; + dst->extradata_size = 0; + if (src->extradata) { + dst->extradata = av_mallocz(src->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!dst->extradata) + return AVERROR(ENOMEM); + memcpy(dst->extradata, src->extradata, src->extradata_size); + dst->extradata_size = src->extradata_size; + } + + return 0; +} + +int avcodec_parameters_from_context(AVCodecParameters *par, + const AVCodecContext *codec) +{ + codec_parameters_reset(par); + + par->codec_type = codec->codec_type; + par->codec_id = codec->codec_id; + par->codec_tag = codec->codec_tag; + + par->bit_rate = codec->bit_rate; + par->bits_per_coded_sample = codec->bits_per_coded_sample; + par->profile = codec->profile; + par->level = codec->level; + + switch (par->codec_type) { + case AVMEDIA_TYPE_VIDEO: + par->format = codec->pix_fmt; + par->width = codec->width; + par->height = codec->height; + par->field_order = codec->field_order; + par->color_range = codec->color_range; + par->color_primaries = codec->color_primaries; + par->color_trc = codec->color_trc; + par->color_space = codec->colorspace; + par->chroma_location = codec->chroma_sample_location; + par->sample_aspect_ratio = codec->sample_aspect_ratio; + par->video_delay = codec->has_b_frames; + break; + case AVMEDIA_TYPE_AUDIO: + par->format = codec->sample_fmt; + par->channel_layout = codec->channel_layout; + par->channels = codec->channels; + par->sample_rate = codec->sample_rate; + par->block_align = codec->block_align; + par->frame_size = codec->frame_size; + par->initial_padding = codec->initial_padding; + par->seek_preroll = codec->seek_preroll; + break; + case AVMEDIA_TYPE_SUBTITLE: + par->width = codec->width; + par->height = codec->height; + break; + } + + if (codec->extradata) { + par->extradata = av_mallocz(codec->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!par->extradata) + return AVERROR(ENOMEM); + memcpy(par->extradata, codec->extradata, codec->extradata_size); + par->extradata_size = codec->extradata_size; + } + + return 0; +} + +int avcodec_parameters_to_context(AVCodecContext *codec, + const AVCodecParameters *par) +{ + codec->codec_type = par->codec_type; + codec->codec_id = par->codec_id; + codec->codec_tag = par->codec_tag; + + codec->bit_rate = par->bit_rate; + codec->bits_per_coded_sample = par->bits_per_coded_sample; + codec->profile = par->profile; + codec->level = par->level; + + switch (par->codec_type) { + case AVMEDIA_TYPE_VIDEO: + codec->pix_fmt = par->format; + codec->width = par->width; + codec->height = par->height; + codec->field_order = par->field_order; + codec->color_range = par->color_range; + codec->color_primaries = par->color_primaries; + codec->color_trc = par->color_trc; + codec->colorspace = par->color_space; + codec->chroma_sample_location = par->chroma_location; + codec->sample_aspect_ratio = par->sample_aspect_ratio; + codec->has_b_frames = par->video_delay; + break; + case AVMEDIA_TYPE_AUDIO: + codec->sample_fmt = par->format; + codec->channel_layout = par->channel_layout; + codec->channels = par->channels; + codec->sample_rate = par->sample_rate; + codec->block_align = par->block_align; + codec->frame_size = par->frame_size; + codec->initial_padding = par->initial_padding; + codec->seek_preroll = par->seek_preroll; + break; + case AVMEDIA_TYPE_SUBTITLE: + codec->width = par->width; + codec->height = par->height; + break; + } + + if (par->extradata) { + av_freep(&codec->extradata); + codec->extradata = av_mallocz(par->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!codec->extradata) + return AVERROR(ENOMEM); + memcpy(codec->extradata, par->extradata, par->extradata_size); + codec->extradata_size = par->extradata_size; + } + + return 0; +} + +#ifdef TEST +int main(void){ + AVCodec *codec = NULL; + int ret = 0; + avcodec_register_all(); + + while (codec = av_codec_next(codec)) { + if (av_codec_is_encoder(codec)) { + if (codec->type == AVMEDIA_TYPE_AUDIO) { + if (!codec->sample_fmts) { + av_log(NULL, AV_LOG_FATAL, "Encoder %s is missing the sample_fmts field\n", codec->name); + ret = 1; + } + } + } + } + return ret; +} +#endif /* TEST */