From c9029736886fef7463c4e2c1c7f0ec9ad1334876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 10 Apr 2024 18:26:09 +0200 Subject: [PATCH] Setup more of the setup --- Common/Common.vcxproj | 6 + Common/Common.vcxproj.filters | 18 + Common/compat.c | 19 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 + Core/HW/Atrac3Standalone.cpp | 55 +++ Core/HW/Atrac3Standalone.h | 5 + Core/HW/SimpleAudioDec.cpp | 3 + ext/at3_standalone/at3_decoders.h | 16 + ext/at3_standalone/atrac3plusdec.c | 16 +- ext/at3_standalone/frame.c | 742 +++++++++++++++++++++++++++++ ext/at3_standalone/mem.c | 507 ++++++++++++++++++++ ext/at3_standalone/pixdesc.h | 394 +++++++++++++++ ext/at3_standalone/util_internal.h | 355 ++++++++++++++ 14 files changed, 2134 insertions(+), 10 deletions(-) create mode 100644 Common/compat.c create mode 100644 Core/HW/Atrac3Standalone.cpp create mode 100644 Core/HW/Atrac3Standalone.h create mode 100644 ext/at3_standalone/at3_decoders.h create mode 100644 ext/at3_standalone/frame.c create mode 100644 ext/at3_standalone/mem.c create mode 100644 ext/at3_standalone/pixdesc.h create mode 100644 ext/at3_standalone/util_internal.h diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index b2d946738b..8b180c6461 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -385,6 +385,7 @@ + @@ -405,14 +406,17 @@ + + + @@ -619,6 +623,7 @@ + @@ -886,6 +891,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index c7c8bb785d..182a250275 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -611,6 +611,18 @@ ext\at3_standalone + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + @@ -1089,6 +1101,12 @@ ext\at3_standalone + + ext\at3_standalone + + + ext\at3_standalone + diff --git a/Common/compat.c b/Common/compat.c new file mode 100644 index 0000000000..e8761981af --- /dev/null +++ b/Common/compat.c @@ -0,0 +1,19 @@ +#include + +void *av_malloc(size_t size) { + return malloc(size); +} + +void *av_mallocz(size_t size) { + return calloc(size, 1); +} + +void av_free(void *p) { + free(p); +} + +void av_freep(void **p) { + void *pp = *p; + free(pp); + *p = 0; +} diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 7c24591a85..e88cd217ae 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -573,6 +573,7 @@ + @@ -1181,6 +1182,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 0918b045f4..cb3f716cc9 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1306,6 +1306,9 @@ Util + + HW + @@ -2088,6 +2091,9 @@ Util + + HW + diff --git a/Core/HW/Atrac3Standalone.cpp b/Core/HW/Atrac3Standalone.cpp new file mode 100644 index 0000000000..3156f91e17 --- /dev/null +++ b/Core/HW/Atrac3Standalone.cpp @@ -0,0 +1,55 @@ +#pragma once + +#include "SimpleAudioDec.h" + +#include "ext/at3_standalone/at3_decoders.h" +extern "C" { +#include "ext/at3_standalone/avcodec.h" +} + +// Uses our standalone AT3/AT3+ decoder derived from FFMPEG +class Atrac3Audio : public AudioDecoder { +public: + Atrac3Audio(PSPAudioType audioType) { + ctx_ = avcodec_alloc_context3(&ff_atrac3p_decoder); + atrac3p_decode_init(ctx_); + frame_ = av_frame_alloc(); + } + ~Atrac3Audio() { + atrac3p_decode_close(ctx_); + av_frame_free(&frame_); + } + + bool Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int *outbytes) override { + int got_frame = 0; + int samples = atrac3p_decode_frame(ctx_, frame_, &got_frame, inbuf, inbytes); + return true; + } + + bool IsOK() const override { return true; } + int GetOutSamples() const override { + return outSamples_; + } + int GetSourcePos() const override { + return srcPos_; + } + + void SetChannels(int channels) override { + // Hmm. ignore for now. + } + + PSPAudioType GetAudioType() const override { return audioType_; } + +private: + AVCodecContext* ctx_ = nullptr; + AVFrame *frame_ = nullptr; + + int outSamples_ = 0; + int srcPos_ = 0; + + PSPAudioType audioType_; +}; + +AudioDecoder *CreateAtrac3Audio(PSPAudioType audioType) { + return new Atrac3Audio(audioType); +} diff --git a/Core/HW/Atrac3Standalone.h b/Core/HW/Atrac3Standalone.h new file mode 100644 index 0000000000..713b1a21a2 --- /dev/null +++ b/Core/HW/Atrac3Standalone.h @@ -0,0 +1,5 @@ +#pragma once + +#include "SimpleAudioDec.h" + +AudioDecoder *CreateAtrac3Audio(PSPAudioType audioType); diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index a6bb246ae3..411a76fe47 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -25,6 +25,7 @@ #include "Core/HW/SimpleAudioDec.h" #include "Core/HW/MediaEngine.h" #include "Core/HW/BufferQueue.h" +#include "Core/HW/Atrac3Standalone.h" #include "ext/minimp3/minimp3.h" @@ -148,6 +149,8 @@ AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz, int c switch (audioType) { case PSP_CODEC_MP3: return new MiniMp3Audio(); + case PSP_CODEC_AT3PLUS: + return CreateAtrac3Audio(audioType); default: return new SimpleAudio(audioType, sampleRateHz, channels); } diff --git a/ext/at3_standalone/at3_decoders.h b/ext/at3_standalone/at3_decoders.h new file mode 100644 index 0000000000..37d28bbd3c --- /dev/null +++ b/ext/at3_standalone/at3_decoders.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +struct AVCodecContext; +struct AVFrame; + +extern "C" { + +#include "avcodec.h" + + int atrac3p_decode_init(AVCodecContext *avctx); + int atrac3p_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, const uint8_t *avpkt_data, int avpkt_size); + int atrac3p_decode_close(AVCodecContext *avctx); + extern AVCodec ff_atrac3p_decoder; +} diff --git a/ext/at3_standalone/atrac3plusdec.c b/ext/at3_standalone/atrac3plusdec.c index 6f2854b8b7..2adb458e0a 100644 --- a/ext/at3_standalone/atrac3plusdec.c +++ b/ext/at3_standalone/atrac3plusdec.c @@ -65,7 +65,7 @@ typedef struct ATRAC3PContext { uint64_t my_channel_layout; ///< current channel layout } ATRAC3PContext; -static av_cold int atrac3p_decode_close(AVCodecContext *avctx) +int atrac3p_decode_close(AVCodecContext *avctx) { ATRAC3PContext *ctx = avctx->priv_data; @@ -144,7 +144,7 @@ static av_cold int set_channel_params(ATRAC3PContext *ctx, return 0; } -static av_cold int atrac3p_decode_init(AVCodecContext *avctx) +int atrac3p_decode_init(AVCodecContext *avctx) { ATRAC3PContext *ctx = avctx->priv_data; int i, ch, ret; @@ -327,11 +327,9 @@ static void reconstruct_frame(ATRAC3PContext *ctx, Atrac3pChanUnitCtx *ch_unit, FFSWAP(Atrac3pWaveSynthParams *, ch_unit->waves_info, ch_unit->waves_info_prev); } -static int atrac3p_decode_frame(AVCodecContext *avctx, void *data, - int *got_frame_ptr, AVPacket *avpkt) +int atrac3p_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, const uint8_t *avpkt_data, int avpkt_size) { ATRAC3PContext *ctx = avctx->priv_data; - AVFrame *frame = data; int i, ret, ch_unit_id, ch_block = 0, out_ch_index = 0, channels_to_process; float **samples_p = (float **)frame->extended_data; @@ -339,7 +337,7 @@ static int atrac3p_decode_frame(AVCodecContext *avctx, void *data, if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - if ((ret = init_get_bits8(&ctx->gb, avpkt->data, avpkt->size)) < 0) + if ((ret = init_get_bits8(&ctx->gb, avpkt_data, avpkt_size)) < 0) return ret; if (get_bits1(&ctx->gb)) { @@ -384,13 +382,12 @@ static int atrac3p_decode_frame(AVCodecContext *avctx, void *data, *got_frame_ptr = 1; - return FFMIN(avctx->block_align, avpkt->size); + return FFMIN(avctx->block_align, avpkt_size); } -/* AVCodec ff_atrac3p_decoder = { .name = "atrac3plus", - .long_name = NULL_IF_CONFIG_SMALL("ATRAC3+ (Adaptive TRansform Acoustic Coding 3+)"), + .long_name = "ATRAC3+ (Adaptive TRansform Acoustic Coding 3+)", .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_ATRAC3P, .capabilities = AV_CODEC_CAP_DR1, @@ -399,4 +396,3 @@ AVCodec ff_atrac3p_decoder = { .close = atrac3p_decode_close, .decode = atrac3p_decode_frame, }; -*/ diff --git a/ext/at3_standalone/frame.c b/ext/at3_standalone/frame.c new file mode 100644 index 0000000000..2966105032 --- /dev/null +++ b/ext/at3_standalone/frame.c @@ -0,0 +1,742 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "channel_layout.h" +// #include "avassert.h" +#include "buffer.h" +#include "common.h" +#include "dict.h" +#include "frame.h" +//#include "imgutils.h" +#include "pixdesc.h" +#include "util_internal.h" +#include "mem.h" +#include "samplefmt.h" + +MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp) +MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_duration) +MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_pos) +MAKE_ACCESSORS(AVFrame, frame, int64_t, channel_layout) +MAKE_ACCESSORS(AVFrame, frame, int, channels) +MAKE_ACCESSORS(AVFrame, frame, int, sample_rate) +MAKE_ACCESSORS(AVFrame, frame, AVDictionary *, metadata) +MAKE_ACCESSORS(AVFrame, frame, int, decode_error_flags) +MAKE_ACCESSORS(AVFrame, frame, int, pkt_size) +MAKE_ACCESSORS(AVFrame, frame, enum AVColorSpace, colorspace) +MAKE_ACCESSORS(AVFrame, frame, enum AVColorRange, color_range) + +#define CHECK_CHANNELS_CONSISTENCY(frame) \ + av_assert2(!(frame)->channel_layout || \ + (frame)->channels == \ + av_get_channel_layout_nb_channels((frame)->channel_layout)) + +AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame) {return &frame->metadata;}; + +#if FF_API_FRAME_QP +int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int qp_type) +{ + av_buffer_unref(&f->qp_table_buf); + + f->qp_table_buf = buf; + +FF_DISABLE_DEPRECATION_WARNINGS + f->qscale_table = buf->data; + f->qstride = stride; + f->qscale_type = qp_type; +FF_ENABLE_DEPRECATION_WARNINGS + + return 0; +} + +int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type) +{ +FF_DISABLE_DEPRECATION_WARNINGS + *stride = f->qstride; + *type = f->qscale_type; +FF_ENABLE_DEPRECATION_WARNINGS + + if (!f->qp_table_buf) + return NULL; + + return f->qp_table_buf->data; +} +#endif + +const char *av_get_colorspace_name(enum AVColorSpace val) +{ + static const char * const name[] = { + [AVCOL_SPC_RGB] = "GBR", + [AVCOL_SPC_BT709] = "bt709", + [AVCOL_SPC_FCC] = "fcc", + [AVCOL_SPC_BT470BG] = "bt470bg", + [AVCOL_SPC_SMPTE170M] = "smpte170m", + [AVCOL_SPC_SMPTE240M] = "smpte240m", + [AVCOL_SPC_YCOCG] = "YCgCo", + }; + if ((unsigned)val >= FF_ARRAY_ELEMS(name)) + return NULL; + return name[val]; +} + +static void get_frame_defaults(AVFrame *frame) +{ + if (frame->extended_data != frame->data) + av_freep(&frame->extended_data); + + memset(frame, 0, sizeof(*frame)); + + frame->pts = + frame->pkt_dts = + frame->pkt_pts = AV_NOPTS_VALUE; + av_frame_set_best_effort_timestamp(frame, AV_NOPTS_VALUE); + av_frame_set_pkt_duration (frame, 0); + av_frame_set_pkt_pos (frame, -1); + av_frame_set_pkt_size (frame, -1); + frame->key_frame = 1; + frame->sample_aspect_ratio = (AVRational){ 0, 1 }; + frame->format = -1; /* unknown */ + frame->extended_data = frame->data; + frame->color_primaries = AVCOL_PRI_UNSPECIFIED; + frame->color_trc = AVCOL_TRC_UNSPECIFIED; + frame->colorspace = AVCOL_SPC_UNSPECIFIED; + frame->color_range = AVCOL_RANGE_UNSPECIFIED; + frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED; +} + +static void free_side_data(AVFrameSideData **ptr_sd) +{ + AVFrameSideData *sd = *ptr_sd; + + av_buffer_unref(&sd->buf); + av_dict_free(&sd->metadata); + av_freep(ptr_sd); +} + +static void wipe_side_data(AVFrame *frame) +{ + int i; + + for (i = 0; i < frame->nb_side_data; i++) { + free_side_data(&frame->side_data[i]); + } + frame->nb_side_data = 0; + + av_freep(&frame->side_data); +} + +AVFrame *av_frame_alloc(void) +{ + AVFrame *frame = av_mallocz(sizeof(*frame)); + + if (!frame) + return NULL; + + frame->extended_data = NULL; + get_frame_defaults(frame); + + return frame; +} + +void av_frame_free(AVFrame **frame) +{ + if (!frame || !*frame) + return; + + av_frame_unref(*frame); + av_freep(frame); +} + +static int get_video_buffer(AVFrame *frame, int align) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int ret, i; + + if (!desc) + return AVERROR(EINVAL); + + if ((ret = av_image_check_size(frame->width, frame->height, 0, NULL)) < 0) + return ret; + + if (!frame->linesize[0]) { + for(i=1; i<=align; i+=i) { + ret = av_image_fill_linesizes(frame->linesize, frame->format, + FFALIGN(frame->width, i)); + if (ret < 0) + return ret; + if (!(frame->linesize[0] & (align-1))) + break; + } + + for (i = 0; i < 4 && frame->linesize[i]; i++) + frame->linesize[i] = FFALIGN(frame->linesize[i], align); + } + + for (i = 0; i < 4 && frame->linesize[i]; i++) { + int h = FFALIGN(frame->height, 32); + if (i == 1 || i == 2) + h = AV_CEIL_RSHIFT(h, desc->log2_chroma_h); + + frame->buf[i] = av_buffer_alloc(frame->linesize[i] * h + 16 + 16/*STRIDE_ALIGN*/ - 1); + if (!frame->buf[i]) + goto fail; + + frame->data[i] = frame->buf[i]->data; + } + if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + av_buffer_unref(&frame->buf[1]); + frame->buf[1] = av_buffer_alloc(AVPALETTE_SIZE); + if (!frame->buf[1]) + goto fail; + frame->data[1] = frame->buf[1]->data; + } + + frame->extended_data = frame->data; + + return 0; +fail: + av_frame_unref(frame); + return AVERROR(ENOMEM); +} + +static int get_audio_buffer(AVFrame *frame, int align) +{ + int channels; + int planar = av_sample_fmt_is_planar(frame->format); + int planes; + int ret, i; + + if (!frame->channels) + frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout); + + channels = frame->channels; + planes = planar ? channels : 1; + + CHECK_CHANNELS_CONSISTENCY(frame); + if (!frame->linesize[0]) { + ret = av_samples_get_buffer_size(&frame->linesize[0], channels, + frame->nb_samples, frame->format, + align); + if (ret < 0) + return ret; + } + + if (planes > AV_NUM_DATA_POINTERS) { + frame->extended_data = av_mallocz_array(planes, + sizeof(*frame->extended_data)); + frame->extended_buf = av_mallocz_array((planes - AV_NUM_DATA_POINTERS), + sizeof(*frame->extended_buf)); + if (!frame->extended_data || !frame->extended_buf) { + av_freep(&frame->extended_data); + av_freep(&frame->extended_buf); + return AVERROR(ENOMEM); + } + frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS; + } else + frame->extended_data = frame->data; + + for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) { + frame->buf[i] = av_buffer_alloc(frame->linesize[0]); + if (!frame->buf[i]) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + frame->extended_data[i] = frame->data[i] = frame->buf[i]->data; + } + for (i = 0; i < planes - AV_NUM_DATA_POINTERS; i++) { + frame->extended_buf[i] = av_buffer_alloc(frame->linesize[0]); + if (!frame->extended_buf[i]) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data; + } + return 0; + +} + +int av_frame_get_buffer(AVFrame *frame, int align) +{ + if (frame->format < 0) + return AVERROR(EINVAL); + + if (frame->width > 0 && frame->height > 0) + return get_video_buffer(frame, align); + else if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0)) + return get_audio_buffer(frame, align); + + return AVERROR(EINVAL); +} + +static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy) +{ + int i; + + dst->key_frame = src->key_frame; + dst->pict_type = src->pict_type; + dst->sample_aspect_ratio = src->sample_aspect_ratio; + dst->pts = src->pts; + dst->repeat_pict = src->repeat_pict; + dst->interlaced_frame = src->interlaced_frame; + dst->top_field_first = src->top_field_first; + dst->palette_has_changed = src->palette_has_changed; + dst->sample_rate = src->sample_rate; + dst->opaque = src->opaque; + dst->pkt_pts = src->pkt_pts; + dst->pkt_dts = src->pkt_dts; + dst->pkt_pos = src->pkt_pos; + dst->pkt_size = src->pkt_size; + dst->pkt_duration = src->pkt_duration; + dst->reordered_opaque = src->reordered_opaque; + dst->quality = src->quality; + dst->best_effort_timestamp = src->best_effort_timestamp; + dst->coded_picture_number = src->coded_picture_number; + dst->display_picture_number = src->display_picture_number; + dst->flags = src->flags; + dst->decode_error_flags = src->decode_error_flags; + dst->color_primaries = src->color_primaries; + dst->color_trc = src->color_trc; + dst->colorspace = src->colorspace; + dst->color_range = src->color_range; + dst->chroma_location = src->chroma_location; + + av_dict_copy(&dst->metadata, src->metadata, 0); + +#if FF_API_ERROR_FRAME +FF_DISABLE_DEPRECATION_WARNINGS + memcpy(dst->error, src->error, sizeof(dst->error)); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + for (i = 0; i < src->nb_side_data; i++) { + const AVFrameSideData *sd_src = src->side_data[i]; + AVFrameSideData *sd_dst; + if ( sd_src->type == AV_FRAME_DATA_PANSCAN + && (src->width != dst->width || src->height != dst->height)) + continue; + if (force_copy) { + sd_dst = av_frame_new_side_data(dst, sd_src->type, + sd_src->size); + if (!sd_dst) { + wipe_side_data(dst); + return AVERROR(ENOMEM); + } + memcpy(sd_dst->data, sd_src->data, sd_src->size); + } else { + sd_dst = av_frame_new_side_data(dst, sd_src->type, 0); + if (!sd_dst) { + wipe_side_data(dst); + return AVERROR(ENOMEM); + } + sd_dst->buf = av_buffer_ref(sd_src->buf); + if (!sd_dst->buf) { + wipe_side_data(dst); + return AVERROR(ENOMEM); + } + sd_dst->data = sd_dst->buf->data; + sd_dst->size = sd_dst->buf->size; + } + av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0); + } + +#if FF_API_FRAME_QP +FF_DISABLE_DEPRECATION_WARNINGS + dst->qscale_table = NULL; + dst->qstride = 0; + dst->qscale_type = 0; + av_buffer_unref(&dst->qp_table_buf); + if (src->qp_table_buf) { + dst->qp_table_buf = av_buffer_ref(src->qp_table_buf); + if (dst->qp_table_buf) { + dst->qscale_table = dst->qp_table_buf->data; + dst->qstride = src->qstride; + dst->qscale_type = src->qscale_type; + } + } +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + return 0; +} + +int av_frame_ref(AVFrame *dst, const AVFrame *src) +{ + int i, ret = 0; + + dst->format = src->format; + dst->width = src->width; + dst->height = src->height; + dst->channels = src->channels; + dst->channel_layout = src->channel_layout; + dst->nb_samples = src->nb_samples; + + ret = frame_copy_props(dst, src, 0); + if (ret < 0) + return ret; + + /* duplicate the frame data if it's not refcounted */ + if (!src->buf[0]) { + ret = av_frame_get_buffer(dst, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(dst, src); + if (ret < 0) + av_frame_unref(dst); + + return ret; + } + + /* ref the buffers */ + for (i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { + if (!src->buf[i]) + continue; + dst->buf[i] = av_buffer_ref(src->buf[i]); + if (!dst->buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + if (src->extended_buf) { + dst->extended_buf = av_mallocz_array(sizeof(*dst->extended_buf), + src->nb_extended_buf); + if (!dst->extended_buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst->nb_extended_buf = src->nb_extended_buf; + + for (i = 0; i < src->nb_extended_buf; i++) { + dst->extended_buf[i] = av_buffer_ref(src->extended_buf[i]); + if (!dst->extended_buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + } + + /* duplicate extended data */ + if (src->extended_data != src->data) { + int ch = src->channels; + + if (!ch) { + ret = AVERROR(EINVAL); + goto fail; + } + CHECK_CHANNELS_CONSISTENCY(src); + + dst->extended_data = av_malloc_array(sizeof(*dst->extended_data), ch); + if (!dst->extended_data) { + ret = AVERROR(ENOMEM); + goto fail; + } + memcpy(dst->extended_data, src->extended_data, sizeof(*src->extended_data) * ch); + } else + dst->extended_data = dst->data; + + memcpy(dst->data, src->data, sizeof(src->data)); + memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); + + return 0; + +fail: + av_frame_unref(dst); + return ret; +} + +AVFrame *av_frame_clone(const AVFrame *src) +{ + AVFrame *ret = av_frame_alloc(); + + if (!ret) + return NULL; + + if (av_frame_ref(ret, src) < 0) + av_frame_free(&ret); + + return ret; +} + +void av_frame_unref(AVFrame *frame) +{ + int i; + + if (!frame) + return; + + wipe_side_data(frame); + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) + av_buffer_unref(&frame->buf[i]); + for (i = 0; i < frame->nb_extended_buf; i++) + av_buffer_unref(&frame->extended_buf[i]); + av_freep(&frame->extended_buf); + av_dict_free(&frame->metadata); +#if FF_API_FRAME_QP + av_buffer_unref(&frame->qp_table_buf); +#endif + + get_frame_defaults(frame); +} + +void av_frame_move_ref(AVFrame *dst, AVFrame *src) +{ + *dst = *src; + if (src->extended_data == src->data) + dst->extended_data = dst->data; + memset(src, 0, sizeof(*src)); + get_frame_defaults(src); +} + +int av_frame_is_writable(AVFrame *frame) +{ + int i, ret = 1; + + /* assume non-refcounted frames are not writable */ + if (!frame->buf[0]) + return 0; + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) + if (frame->buf[i]) + ret &= !!av_buffer_is_writable(frame->buf[i]); + for (i = 0; i < frame->nb_extended_buf; i++) + ret &= !!av_buffer_is_writable(frame->extended_buf[i]); + + return ret; +} + +int av_frame_make_writable(AVFrame *frame) +{ + AVFrame tmp; + int ret; + + if (!frame->buf[0]) + return AVERROR(EINVAL); + + if (av_frame_is_writable(frame)) + return 0; + + memset(&tmp, 0, sizeof(tmp)); + tmp.format = frame->format; + tmp.width = frame->width; + tmp.height = frame->height; + tmp.channels = frame->channels; + tmp.channel_layout = frame->channel_layout; + tmp.nb_samples = frame->nb_samples; + ret = av_frame_get_buffer(&tmp, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + ret = av_frame_copy_props(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + av_frame_unref(frame); + + *frame = tmp; + if (tmp.data == tmp.extended_data) + frame->extended_data = frame->data; + + return 0; +} + +int av_frame_copy_props(AVFrame *dst, const AVFrame *src) +{ + return frame_copy_props(dst, src, 1); +} + +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane) +{ + uint8_t *data; + int planes, i; + + if (frame->nb_samples) { + int channels = frame->channels; + if (!channels) + return NULL; + CHECK_CHANNELS_CONSISTENCY(frame); + planes = av_sample_fmt_is_planar(frame->format) ? channels : 1; + } else + planes = 4; + + if (plane < 0 || plane >= planes || !frame->extended_data[plane]) + return NULL; + data = frame->extended_data[plane]; + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf) && frame->buf[i]; i++) { + AVBufferRef *buf = frame->buf[i]; + if (data >= buf->data && data < buf->data + buf->size) + return buf; + } + for (i = 0; i < frame->nb_extended_buf; i++) { + AVBufferRef *buf = frame->extended_buf[i]; + if (data >= buf->data && data < buf->data + buf->size) + return buf; + } + return NULL; +} + +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size) +{ + AVFrameSideData *ret, **tmp; + + if (frame->nb_side_data > INT_MAX / sizeof(*frame->side_data) - 1) + return NULL; + + tmp = av_realloc(frame->side_data, + (frame->nb_side_data + 1) * sizeof(*frame->side_data)); + if (!tmp) + return NULL; + frame->side_data = tmp; + + ret = av_mallocz(sizeof(*ret)); + if (!ret) + return NULL; + + if (size > 0) { + ret->buf = av_buffer_alloc(size); + if (!ret->buf) { + av_freep(&ret); + return NULL; + } + + ret->data = ret->buf->data; + ret->size = size; + } + ret->type = type; + + frame->side_data[frame->nb_side_data++] = ret; + + return ret; +} + +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type) +{ + int i; + + for (i = 0; i < frame->nb_side_data; i++) { + if (frame->side_data[i]->type == type) + return frame->side_data[i]; + } + return NULL; +} + +static int frame_copy_video(AVFrame *dst, const AVFrame *src) +{ + const uint8_t *src_data[4]; + int i, planes; + + if (dst->width < src->width || + dst->height < src->height) + return AVERROR(EINVAL); + + planes = av_pix_fmt_count_planes(dst->format); + for (i = 0; i < planes; i++) + if (!dst->data[i] || !src->data[i]) + return AVERROR(EINVAL); + + memcpy(src_data, src->data, sizeof(src_data)); + av_image_copy(dst->data, dst->linesize, + src_data, src->linesize, + dst->format, src->width, src->height); + + return 0; +} + +static int frame_copy_audio(AVFrame *dst, const AVFrame *src) +{ + int planar = av_sample_fmt_is_planar(dst->format); + int channels = dst->channels; + int planes = planar ? channels : 1; + int i; + + if (dst->nb_samples != src->nb_samples || + dst->channels != src->channels || + dst->channel_layout != src->channel_layout) + return AVERROR(EINVAL); + + CHECK_CHANNELS_CONSISTENCY(src); + + for (i = 0; i < planes; i++) + if (!dst->extended_data[i] || !src->extended_data[i]) + return AVERROR(EINVAL); + + av_samples_copy(dst->extended_data, src->extended_data, 0, 0, + dst->nb_samples, channels, dst->format); + + return 0; +} + +int av_frame_copy(AVFrame *dst, const AVFrame *src) +{ + if (dst->format != src->format || dst->format < 0) + return AVERROR(EINVAL); + + if (dst->width > 0 && dst->height > 0) + return frame_copy_video(dst, src); + else if (dst->nb_samples > 0 && dst->channel_layout) + return frame_copy_audio(dst, src); + + return AVERROR(EINVAL); +} + +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type) +{ + int i; + + for (i = 0; i < frame->nb_side_data; i++) { + AVFrameSideData *sd = frame->side_data[i]; + if (sd->type == type) { + free_side_data(&frame->side_data[i]); + frame->side_data[i] = frame->side_data[frame->nb_side_data - 1]; + frame->nb_side_data--; + } + } +} + +const char *av_frame_side_data_name(enum AVFrameSideDataType type) +{ + switch(type) { + case AV_FRAME_DATA_PANSCAN: return "AVPanScan"; + case AV_FRAME_DATA_A53_CC: return "ATSC A53 Part 4 Closed Captions"; + case AV_FRAME_DATA_STEREO3D: return "Stereoscopic 3d metadata"; + case AV_FRAME_DATA_MATRIXENCODING: return "AVMatrixEncoding"; + case AV_FRAME_DATA_DOWNMIX_INFO: return "Metadata relevant to a downmix procedure"; + case AV_FRAME_DATA_REPLAYGAIN: return "AVReplayGain"; + case AV_FRAME_DATA_DISPLAYMATRIX: return "3x3 displaymatrix"; + case AV_FRAME_DATA_AFD: return "Active format description"; + case AV_FRAME_DATA_MOTION_VECTORS: return "Motion vectors"; + case AV_FRAME_DATA_SKIP_SAMPLES: return "Skip samples"; + case AV_FRAME_DATA_AUDIO_SERVICE_TYPE: return "Audio service type"; + case AV_FRAME_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata"; + case AV_FRAME_DATA_GOP_TIMECODE: return "GOP timecode"; + } + return NULL; +} diff --git a/ext/at3_standalone/mem.c b/ext/at3_standalone/mem.c new file mode 100644 index 0000000000..8dfaad8271 --- /dev/null +++ b/ext/at3_standalone/mem.c @@ -0,0 +1,507 @@ +/* + * default memory allocator for libavutil + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * default memory allocator for libavutil + */ + +#define _XOPEN_SOURCE 600 + +#include "config.h" + +#include +#include +#include +#include +#if HAVE_MALLOC_H +#include +#endif + +#include "avassert.h" +#include "avutil.h" +#include "common.h" +#include "dynarray.h" +#include "intreadwrite.h" +#include "mem.h" + +#ifdef MALLOC_PREFIX + +#define malloc AV_JOIN(MALLOC_PREFIX, malloc) +#define memalign AV_JOIN(MALLOC_PREFIX, memalign) +#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign) +#define realloc AV_JOIN(MALLOC_PREFIX, realloc) +#define free AV_JOIN(MALLOC_PREFIX, free) + +void *malloc(size_t size); +void *memalign(size_t align, size_t size); +int posix_memalign(void **ptr, size_t align, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); + +#endif /* MALLOC_PREFIX */ + +#include "mem_internal.h" + +#define ALIGN (HAVE_AVX ? 32 : 16) + +/* NOTE: if you want to override these functions with your own + * implementations (not recommended) you have to link libav* as + * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. + * Note that this will cost performance. */ + +static size_t max_alloc_size= INT_MAX; + +void av_max_alloc(size_t max){ + max_alloc_size = max; +} + +void *av_malloc(size_t size) +{ + void *ptr = NULL; +#if CONFIG_MEMALIGN_HACK + long diff; +#endif + + /* let's disallow possibly ambiguous cases */ + if (size > (max_alloc_size - 32)) + return NULL; + +#if CONFIG_MEMALIGN_HACK + ptr = malloc(size + ALIGN); + if (!ptr) + return ptr; + diff = ((~(long)ptr)&(ALIGN - 1)) + 1; + ptr = (char *)ptr + diff; + ((char *)ptr)[-1] = diff; +#elif HAVE_POSIX_MEMALIGN + if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation + if (posix_memalign(&ptr, ALIGN, size)) + ptr = NULL; +#elif HAVE_ALIGNED_MALLOC + ptr = _aligned_malloc(size, ALIGN); +#elif HAVE_MEMALIGN +#ifndef __DJGPP__ + ptr = memalign(ALIGN, size); +#else + ptr = memalign(size, ALIGN); +#endif + /* Why 64? + * Indeed, we should align it: + * on 4 for 386 + * on 16 for 486 + * on 32 for 586, PPro - K6-III + * on 64 for K7 (maybe for P3 too). + * Because L1 and L2 caches are aligned on those values. + * But I don't want to code such logic here! + */ + /* Why 32? + * For AVX ASM. SSE / NEON needs only 16. + * Why not larger? Because I did not see a difference in benchmarks ... + */ + /* benchmarks with P3 + * memalign(64) + 1 3071, 3051, 3032 + * memalign(64) + 2 3051, 3032, 3041 + * memalign(64) + 4 2911, 2896, 2915 + * memalign(64) + 8 2545, 2554, 2550 + * memalign(64) + 16 2543, 2572, 2563 + * memalign(64) + 32 2546, 2545, 2571 + * memalign(64) + 64 2570, 2533, 2558 + * + * BTW, malloc seems to do 8-byte alignment by default here. + */ +#else + ptr = malloc(size); +#endif + if(!ptr && !size) { + size = 1; + ptr= av_malloc(1); + } +#if CONFIG_MEMORY_POISONING + if (ptr) + memset(ptr, FF_MEMORY_POISON, size); +#endif + return ptr; +} + +void *av_realloc(void *ptr, size_t size) +{ +#if CONFIG_MEMALIGN_HACK + int diff; +#endif + + /* let's disallow possibly ambiguous cases */ + if (size > (max_alloc_size - 32)) + return NULL; + +#if CONFIG_MEMALIGN_HACK + //FIXME this isn't aligned correctly, though it probably isn't needed + if (!ptr) + return av_malloc(size); + diff = ((char *)ptr)[-1]; + av_assert0(diff>0 && diff<=ALIGN); + ptr = realloc((char *)ptr - diff, size + diff); + if (ptr) + ptr = (char *)ptr + diff; + return ptr; +#elif HAVE_ALIGNED_MALLOC + return _aligned_realloc(ptr, size + !size, ALIGN); +#else + return realloc(ptr, size + !size); +#endif +} + +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) +{ + size_t size; + void *r; + + if (av_size_mult(elsize, nelem, &size)) { + av_free(ptr); + return NULL; + } + r = av_realloc(ptr, size); + if (!r && size) + av_free(ptr); + return r; +} + +int av_reallocp(void *ptr, size_t size) +{ + void *val; + + if (!size) { + av_freep(ptr); + return 0; + } + + memcpy(&val, ptr, sizeof(val)); + val = av_realloc(val, size); + + if (!val) { + av_freep(ptr); + return AVERROR(ENOMEM); + } + + memcpy(ptr, &val, sizeof(val)); + return 0; +} + +void *av_realloc_array(void *ptr, size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_realloc(ptr, nmemb * size); +} + +int av_reallocp_array(void *ptr, size_t nmemb, size_t size) +{ + void *val; + + memcpy(&val, ptr, sizeof(val)); + val = av_realloc_f(val, nmemb, size); + memcpy(ptr, &val, sizeof(val)); + if (!val && nmemb && size) + return AVERROR(ENOMEM); + + return 0; +} + +void av_free(void *ptr) +{ +#if CONFIG_MEMALIGN_HACK + if (ptr) { + int v= ((char *)ptr)[-1]; + av_assert0(v>0 && v<=ALIGN); + free((char *)ptr - v); + } +#elif HAVE_ALIGNED_MALLOC + _aligned_free(ptr); +#else + free(ptr); +#endif +} + +void av_freep(void *arg) +{ + void *val; + + memcpy(&val, arg, sizeof(val)); + memcpy(arg, &(void *){ NULL }, sizeof(val)); + av_free(val); +} + +void *av_mallocz(size_t size) +{ + void *ptr = av_malloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +void *av_calloc(size_t nmemb, size_t size) +{ + if (size <= 0 || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + +char *av_strdup(const char *s) +{ + char *ptr = NULL; + if (s) { + size_t len = strlen(s) + 1; + ptr = av_realloc(NULL, len); + if (ptr) + memcpy(ptr, s, len); + } + return ptr; +} + +char *av_strndup(const char *s, size_t len) +{ + char *ret = NULL, *end; + + if (!s) + return NULL; + + end = memchr(s, 0, len); + if (end) + len = end - s; + + ret = av_realloc(NULL, len + 1); + if (!ret) + return NULL; + + memcpy(ret, s, len); + ret[len] = 0; + return ret; +} + +void *av_memdup(const void *p, size_t size) +{ + void *ptr = NULL; + if (p) { + ptr = av_malloc(size); + if (ptr) + memcpy(ptr, p, size); + } + return ptr; +} + +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem) +{ + void **tab; + memcpy(&tab, tab_ptr, sizeof(tab)); + + AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { + tab[*nb_ptr] = elem; + memcpy(tab_ptr, &tab, sizeof(tab)); + }, { + return AVERROR(ENOMEM); + }); + return 0; +} + +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem) +{ + void **tab; + memcpy(&tab, tab_ptr, sizeof(tab)); + + AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { + tab[*nb_ptr] = elem; + memcpy(tab_ptr, &tab, sizeof(tab)); + }, { + *nb_ptr = 0; + av_freep(tab_ptr); + }); +} + +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data) +{ + uint8_t *tab_elem_data = NULL; + + AV_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, { + tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size; + if (elem_data) + memcpy(tab_elem_data, elem_data, elem_size); + else if (CONFIG_MEMORY_POISONING) + memset(tab_elem_data, FF_MEMORY_POISON, elem_size); + }, { + av_freep(tab_ptr); + *nb_ptr = 0; + }); + return tab_elem_data; +} + +static void fill16(uint8_t *dst, int len) +{ + uint32_t v = AV_RN16(dst - 2); + + v |= v << 16; + + while (len >= 4) { + AV_WN32(dst, v); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-2]; + dst++; + } +} + +static void fill24(uint8_t *dst, int len) +{ +#if HAVE_BIGENDIAN + uint32_t v = AV_RB24(dst - 3); + uint32_t a = v << 8 | v >> 16; + uint32_t b = v << 16 | v >> 8; + uint32_t c = v << 24 | v; +#else + uint32_t v = AV_RL24(dst - 3); + uint32_t a = v | v << 24; + uint32_t b = v >> 8 | v << 16; + uint32_t c = v >> 16 | v << 8; +#endif + + while (len >= 12) { + AV_WN32(dst, a); + AV_WN32(dst + 4, b); + AV_WN32(dst + 8, c); + dst += 12; + len -= 12; + } + + if (len >= 4) { + AV_WN32(dst, a); + dst += 4; + len -= 4; + } + + if (len >= 4) { + AV_WN32(dst, b); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-3]; + dst++; + } +} + +static void fill32(uint8_t *dst, int len) +{ + uint32_t v = AV_RN32(dst - 4); + + while (len >= 4) { + AV_WN32(dst, v); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-4]; + dst++; + } +} + +void av_memcpy_backptr(uint8_t *dst, int back, int cnt) +{ + const uint8_t *src = &dst[-back]; + if (!back) + return; + + if (back == 1) { + memset(dst, *src, cnt); + } else if (back == 2) { + fill16(dst, cnt); + } else if (back == 3) { + fill24(dst, cnt); + } else if (back == 4) { + fill32(dst, cnt); + } else { + if (cnt >= 16) { + int blocklen = back; + while (cnt > blocklen) { + memcpy(dst, src, blocklen); + dst += blocklen; + cnt -= blocklen; + blocklen <<= 1; + } + memcpy(dst, src, cnt); + return; + } + if (cnt >= 8) { + AV_COPY32U(dst, src); + AV_COPY32U(dst + 4, src + 4); + src += 8; + dst += 8; + cnt -= 8; + } + if (cnt >= 4) { + AV_COPY32U(dst, src); + src += 4; + dst += 4; + cnt -= 4; + } + if (cnt >= 2) { + AV_COPY16U(dst, src); + src += 2; + dst += 2; + cnt -= 2; + } + if (cnt) + *dst = *src; + } +} + +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) +{ + if (min_size < *size) + return ptr; + + min_size = FFMAX(min_size + min_size / 16 + 32, min_size); + + ptr = av_realloc(ptr, min_size); + /* we could set this to the unmodified min_size but this is safer + * if the user lost the ptr and uses NULL now + */ + if (!ptr) + min_size = 0; + + *size = min_size; + + return ptr; +} + +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size) +{ + ff_fast_malloc(ptr, size, min_size, 0); +} + +void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size) +{ + ff_fast_malloc(ptr, size, min_size, 1); +} diff --git a/ext/at3_standalone/pixdesc.h b/ext/at3_standalone/pixdesc.h new file mode 100644 index 0000000000..b1d218db48 --- /dev/null +++ b/ext/at3_standalone/pixdesc.h @@ -0,0 +1,394 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include + +#include "attributes.h" +#include "pixfmt.h" +#include "version.h" + +typedef struct AVComponentDescriptor { + /** + * Which of the 4 planes contains the component. + */ + int plane; + + /** + * Number of elements between 2 horizontally consecutive pixels. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int step; + + /** + * Number of elements before the component of the first pixel. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int offset; + + /** + * Number of least significant bits that must be shifted away + * to get the value. + */ + int shift; + + /** + * Number of bits in the component. + */ + int depth; + +#if FF_API_PLUS1_MINUS1 + /** deprecated, use step instead */ + attribute_deprecated int step_minus1; + + /** deprecated, use depth instead */ + attribute_deprecated int depth_minus1; + + /** deprecated, use offset instead */ + attribute_deprecated int offset_plus1; +#endif +} AVComponentDescriptor; + +/** + * Descriptor that unambiguously describes how the bits of a pixel are + * stored in the up to 4 data planes of an image. It also stores the + * subsampling factors and number of components. + * + * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV + * and all the YUV variants) AVPixFmtDescriptor just stores how values + * are stored not what these values represent. + */ +typedef struct AVPixFmtDescriptor { + const char *name; + uint8_t nb_components; ///< The number of components each pixel has, (1-4) + + /** + * Amount to shift the luma width right to find the chroma width. + * For YV12 this is 1 for example. + * chroma_width = -((-luma_width) >> log2_chroma_w) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_w; ///< chroma_width = -((-luma_width )>>log2_chroma_w) + + /** + * Amount to shift the luma height right to find the chroma height. + * For YV12 this is 1 for example. + * chroma_height= -((-luma_height) >> log2_chroma_h) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_h; + + /** + * Combination of AV_PIX_FMT_FLAG_... flags. + */ + uint64_t flags; + + /** + * Parameters that describe how pixels are packed. + * If the format has 1 or 2 components, then luma is 0. + * If the format has 3 or 4 components: + * if the RGB flag is set then 0 is red, 1 is green and 2 is blue; + * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V. + * + * If present, the Alpha channel is always the last component. + */ + AVComponentDescriptor comp[4]; + + /** + * Alternative comma-separated names. + */ + const char *alias; +} AVPixFmtDescriptor; + +/** + * Pixel format is big-endian. + */ +#define AV_PIX_FMT_FLAG_BE (1 << 0) +/** + * Pixel format has a palette in data[1], values are indexes in this palette. + */ +#define AV_PIX_FMT_FLAG_PAL (1 << 1) +/** + * All values of a component are bit-wise packed end to end. + */ +#define AV_PIX_FMT_FLAG_BITSTREAM (1 << 2) +/** + * Pixel format is an HW accelerated format. + */ +#define AV_PIX_FMT_FLAG_HWACCEL (1 << 3) +/** + * At least one pixel component is not in the first data plane. + */ +#define AV_PIX_FMT_FLAG_PLANAR (1 << 4) +/** + * The pixel format contains RGB-like data (as opposed to YUV/grayscale). + */ +#define AV_PIX_FMT_FLAG_RGB (1 << 5) + +/** + * The pixel format is "pseudo-paletted". This means that it contains a + * fixed palette in the 2nd plane but the palette is fixed/constant for each + * PIX_FMT. This allows interpreting the data as if it was PAL8, which can + * in some cases be simpler. Or the data can be interpreted purely based on + * the pixel format without using the palette. + * An example of a pseudo-paletted format is AV_PIX_FMT_GRAY8 + */ +#define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6) + +/** + * The pixel format has an alpha channel. This is set on all formats that + * support alpha in some way. The exception is AV_PIX_FMT_PAL8, which can + * carry alpha as part of the palette. Details are explained in the + * AVPixelFormat enum, and are also encoded in the corresponding + * AVPixFmtDescriptor. + * + * The alpha is always straight, never pre-multiplied. + * + * If a codec or a filter does not support alpha, it should set all alpha to + * opaque, or use the equivalent pixel formats without alpha component, e.g. + * AV_PIX_FMT_RGB0 (or AV_PIX_FMT_RGB24 etc.) instead of AV_PIX_FMT_RGBA. + */ +#define AV_PIX_FMT_FLAG_ALPHA (1 << 7) + +/** + * Read a line from an image, and write the values of the + * pixel format component c to dst. + * + * @param data the array containing the pointers to the planes of the image + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to read + * @param y the vertical coordinate of the first pixel to read + * @param w the width of the line to read, that is the number of + * values to write to dst + * @param read_pal_component if not zero and the format is a paletted + * format writes the values corresponding to the palette + * component c in data[1] to dst, rather than the palette indexes in + * data[0]. The behavior is undefined if the format is not paletted. + */ +void av_read_image_line(uint16_t *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component); + +/** + * Write the values from src to the pixel format component c of an + * image line. + * + * @param src array containing the values to write + * @param data the array containing the pointers to the planes of the + * image to write into. It is supposed to be zeroed. + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to write + * @param y the vertical coordinate of the first pixel to write + * @param w the width of the line to write, that is the number of + * values to write to the image line + */ +void av_write_image_line(const uint16_t *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w); + +/** + * Return the pixel format corresponding to name. + * + * If there is no pixel format with name name, then looks for a + * pixel format with the name corresponding to the native endian + * format of name. + * For example in a little-endian system, first looks for "gray16", + * then for "gray16le". + * + * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE. + */ +enum AVPixelFormat av_get_pix_fmt(const char *name); + +/** + * Return the short name for a pixel format, NULL in case pix_fmt is + * unknown. + * + * @see av_get_pix_fmt(), av_get_pix_fmt_string() + */ +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); + +/** + * Print in buf the string corresponding to the pixel format with + * number pix_fmt, or a header if pix_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param pix_fmt the number of the pixel format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + */ +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt); + +/** + * Return the number of bits per pixel used by the pixel format + * described by pixdesc. Note that this is not the same as the number + * of bits per sample. + * + * The returned number of bits refers to the number of bits actually + * used for storing the pixel information, that is padding bits are + * not counted. + */ +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * Return the number of bits per pixel for the pixel format + * described by pixdesc, including any padding or unused bits. + */ +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * @return a pixel format descriptor for provided pixel format or NULL if + * this pixel format is unknown. + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt); + +/** + * Iterate over all pixel format descriptors known to libavutil. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev); + +/** + * @return an AVPixelFormat id described by desc, or AV_PIX_FMT_NONE if desc + * is not a valid pointer to a pixel format descriptor. + */ +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * See av_get_chroma_sub_sample() for a function that asserts a + * valid pixel format instead of returning an error code. + * Its recommended that you use avcodec_get_chroma_sub_sample unless + * you do check the return code! + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w (horizontal/width shift) + * @param[out] v_shift store log2_chroma_h (vertical/height shift) + * + * @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format + */ +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift); + +/** + * @return number of planes in pix_fmt, a negative AVERROR if pix_fmt is not a + * valid pixel format. + */ +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); + +/** + * Utility function to swap the endianness of a pixel format. + * + * @param[in] pix_fmt the pixel format + * + * @return pixel format with swapped endianness if it exists, + * otherwise AV_PIX_FMT_NONE + */ +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +/** + * @return the name for provided color range or NULL if unknown. + */ +const char *av_color_range_name(enum AVColorRange range); + +/** + * @return the name for provided color primaries or NULL if unknown. + */ +const char *av_color_primaries_name(enum AVColorPrimaries primaries); + +/** + * @return the name for provided color transfer or NULL if unknown. + */ +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer); + +/** + * @return the name for provided color space or NULL if unknown. + */ +const char *av_color_space_name(enum AVColorSpace space); + +/** + * @return the name for provided chroma location or NULL if unknown. + */ +const char *av_chroma_location_name(enum AVChromaLocation location); + +#endif /* AVUTIL_PIXDESC_H */ diff --git a/ext/at3_standalone/util_internal.h b/ext/at3_standalone/util_internal.h new file mode 100644 index 0000000000..3a69614c65 --- /dev/null +++ b/ext/at3_standalone/util_internal.h @@ -0,0 +1,355 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal API header + */ + +#ifndef AVUTIL_INTERNAL_H +#define AVUTIL_INTERNAL_H + +#if !defined(DEBUG) && !defined(NDEBUG) +# define NDEBUG +#endif + +#include +#include +#include +#include +#include "config.h" +#include "attributes.h" +#include "dict.h" +#include "macros.h" +#include "pixfmt.h" +#include "version.h" + +#if ARCH_X86 +# include "x86/emms.h" +#endif + +#ifndef emms_c +# define emms_c() while(0) +#endif + +#ifndef attribute_align_arg +#if ARCH_X86_32 && AV_GCC_VERSION_AT_LEAST(4,2) +# define attribute_align_arg __attribute__((force_align_arg_pointer)) +#else +# define attribute_align_arg +#endif +#endif + +#if defined(_MSC_VER) && CONFIG_SHARED +# define av_export __declspec(dllimport) +#else +# define av_export +#endif + +#if HAVE_PRAGMA_DEPRECATED +# if defined(__ICL) || defined (__INTEL_COMPILER) +# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478)) +# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) +# elif defined(_MSC_VER) +# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:4996)) +# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) +# else +# define FF_DISABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define FF_ENABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"") +# endif +#else +# define FF_DISABLE_DEPRECATION_WARNINGS +# define FF_ENABLE_DEPRECATION_WARNINGS +#endif + + +#define FF_MEMORY_POISON 0x2a + +#define MAKE_ACCESSORS(str, name, type, field) \ + type av_##name##_get_##field(const str *s) { return s->field; } \ + void av_##name##_set_##field(str *s, type v) { s->field = v; } + +// Some broken preprocessors need a second expansion +// to be forced to tokenize __VA_ARGS__ +#define E1(x) x + +/* Check if the hard coded offset of a struct member still matches reality. + * Induce a compilation failure if not. + */ +#define AV_CHECK_OFFSET(s, m, o) struct check_##o { \ + int x_##o[offsetof(s, m) == o? 1: -1]; \ + } + +#define LOCAL_ALIGNED_A(a, t, v, s, o, ...) \ + uint8_t la_##v[sizeof(t s o) + (a)]; \ + t (*v) o = (void *)FFALIGN((uintptr_t)la_##v, a) + +#define LOCAL_ALIGNED_D(a, t, v, s, o, ...) \ + DECLARE_ALIGNED(a, t, la_##v) s o; \ + t (*v) o = la_##v + +#define LOCAL_ALIGNED(a, t, v, ...) E1(LOCAL_ALIGNED_A(a, t, v, __VA_ARGS__,,)) + +#if HAVE_LOCAL_ALIGNED_8 +# define LOCAL_ALIGNED_8(t, v, ...) E1(LOCAL_ALIGNED_D(8, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_8(t, v, ...) LOCAL_ALIGNED(8, t, v, __VA_ARGS__) +#endif + +#if HAVE_LOCAL_ALIGNED_16 +# define LOCAL_ALIGNED_16(t, v, ...) E1(LOCAL_ALIGNED_D(16, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_16(t, v, ...) LOCAL_ALIGNED(16, t, v, __VA_ARGS__) +#endif + +#if HAVE_LOCAL_ALIGNED_32 +# define LOCAL_ALIGNED_32(t, v, ...) E1(LOCAL_ALIGNED_D(32, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_32(t, v, ...) LOCAL_ALIGNED(32, t, v, __VA_ARGS__) +#endif + +#define FF_ALLOC_OR_GOTO(ctx, p, size, label)\ +{\ + p = av_malloc(size);\ + if (!(p) && (size) != 0) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOCZ_OR_GOTO(ctx, p, size, label)\ +{\ + p = av_mallocz(size);\ + if (!(p) && (size) != 0) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOC_ARRAY_OR_GOTO(ctx, p, nelem, elsize, label)\ +{\ + p = av_malloc_array(nelem, elsize);\ + if (!p) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOCZ_ARRAY_OR_GOTO(ctx, p, nelem, elsize, label)\ +{\ + p = av_mallocz_array(nelem, elsize);\ + if (!p) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#include "libm.h" + +/** + * Return NULL if CONFIG_SMALL is true, otherwise the argument + * without modification. Used to disable the definition of strings + * (for example AVCodec long_names). + */ +#if CONFIG_SMALL +# define NULL_IF_CONFIG_SMALL(x) NULL +#else +# define NULL_IF_CONFIG_SMALL(x) x +#endif + +/** + * Define a function with only the non-default version specified. + * + * On systems with ELF shared libraries, all symbols exported from + * FFmpeg libraries are tagged with the name and major version of the + * library to which they belong. If a function is moved from one + * library to another, a wrapper must be retained in the original + * location to preserve binary compatibility. + * + * Functions defined with this macro will never be used to resolve + * symbols by the build-time linker. + * + * @param type return type of function + * @param name name of function + * @param args argument list of function + * @param ver version tag to assign function + */ +#if HAVE_SYMVER_ASM_LABEL +# define FF_SYMVER(type, name, args, ver) \ + type ff_##name args __asm__ (EXTERN_PREFIX #name "@" ver); \ + type ff_##name args +#elif HAVE_SYMVER_GNU_ASM +# define FF_SYMVER(type, name, args, ver) \ + __asm__ (".symver ff_" #name "," EXTERN_PREFIX #name "@" ver); \ + type ff_##name args; \ + type ff_##name args +#endif + +/** + * Return NULL if a threading library has not been enabled. + * Used to disable threading functions in AVCodec definitions + * when not needed. + */ +#if HAVE_THREADS +# define ONLY_IF_THREADS_ENABLED(x) x +#else +# define ONLY_IF_THREADS_ENABLED(x) NULL +#endif + +/** + * Log a generic warning message about a missing feature. + * + * @param[in] avc a pointer to an arbitrary struct of which the first + * field is a pointer to an AVClass struct + * @param[in] msg string containing the name of the missing feature + */ +void avpriv_report_missing_feature(void *avc, + const char *msg, ...) av_printf_format(2, 3); + +/** + * Log a generic warning message about a missing feature. + * Additionally request that a sample showcasing the feature be uploaded. + * + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] msg string containing the name of the missing feature + */ +void avpriv_request_sample(void *avc, + const char *msg, ...) av_printf_format(2, 3); + +#if HAVE_LIBC_MSVCRT +#include +#if defined(_VC_CRT_MAJOR_VERSION) && _VC_CRT_MAJOR_VERSION < 14 +#pragma comment(linker, "/include:" EXTERN_PREFIX "avpriv_strtod") +#pragma comment(linker, "/include:" EXTERN_PREFIX "avpriv_snprintf") +#endif + +#define avpriv_open ff_open +#define PTRDIFF_SPECIFIER "Id" +#define SIZE_SPECIFIER "Iu" +#else +#define PTRDIFF_SPECIFIER "td" +#define SIZE_SPECIFIER "zu" +#endif + +#ifdef DEBUG +# define ff_dlog(ctx, ...) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__) +#else +# define ff_dlog(ctx, ...) do { if (0) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) +#endif + +/** + * Clip and convert a double value into the long long amin-amax range. + * This function is needed because conversion of floating point to integers when + * it does not fit in the integer's representation does not necessarily saturate + * correctly (usually converted to a cvttsd2si on x86) which saturates numbers + * > INT64_MAX to INT64_MIN. The standard marks such conversions as undefined + * behavior, allowing this sort of mathematically bogus conversions. This provides + * a safe alternative that is slower obviously but assures safety and better + * mathematical behavior. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int64_t ff_rint64_clip(double a, int64_t amin, int64_t amax) +{ + int64_t res; +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + // INT64_MAX+1,INT64_MIN are exactly representable as IEEE doubles + // do range checks first + if (a >= 9223372036854775808.0) + return amax; + if (a <= -9223372036854775808.0) + return amin; + + // safe to call llrint and clip accordingly + res = llrint(a); + if (res > amax) + return amax; + if (res < amin) + return amin; + return res; +} + +/** + * Compute 10^x for floating point values. Note: this function is by no means + * "correctly rounded", and is meant as a fast, reasonably accurate approximation. + * For instance, maximum relative error for the double precision variant is + * ~ 1e-13 for very small and very large values. + * This is ~2x faster than GNU libm's approach, which is still off by 2ulp on + * some inputs. + * @param x exponent + * @return 10^x + */ +static av_always_inline double ff_exp10(double x) +{ + return exp2(M_LOG2_10 * x); +} + +static av_always_inline float ff_exp10f(float x) +{ + return exp2f(M_LOG2_10 * x); +} + +/** + * Compute x^y for floating point x, y. Note: this function is faster than the + * libm variant due to mainly 2 reasons: + * 1. It does not handle any edge cases. In particular, this is only guaranteed + * to work correctly for x > 0. + * 2. It is not as accurate as a standard nearly "correctly rounded" libm variant. + * @param x base + * @param y exponent + * @return x^y + */ +static av_always_inline float ff_fast_powf(float x, float y) +{ + return expf(logf(x) * y); +} + + +/** + * A wrapper for open() setting O_CLOEXEC. + */ +av_warn_unused_result +int avpriv_open(const char *filename, int flags, ...); + +int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt); + +static av_always_inline av_const int avpriv_mirror(int x, int w) +{ + if (!w) + return 0; + + while ((unsigned)x > (unsigned)w) { + x = -x; + if (x < 0) + x += 2 * w; + } + return x; +} + +void ff_check_pixfmt_descriptors(void); + +extern const uint8_t ff_reverse[256]; + +#endif /* AVUTIL_INTERNAL_H */