1080 lines · 29.5 KB · C
RawDownload
/* * 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 <string.h> #include "config.h" #include "libavutil/avassert.h"#include "libavutil/buffer.h"#include "libavutil/common.h"#include "libavutil/mem.h"#include "libavutil/opt.h" #include "avcodec.h"#include "cbs.h"#include "cbs_internal.h"#include "libavutil/refstruct.h"  static const CodedBitstreamType *const cbs_type_table[] = {#if CONFIG_CBS_AV1    &ff_cbs_type_av1,#endif#if CONFIG_CBS_H264    &ff_cbs_type_h264,#endif#if CONFIG_CBS_H265    &ff_cbs_type_h265,#endif#if CONFIG_CBS_H266    &ff_cbs_type_h266,#endif#if CONFIG_CBS_JPEG    &ff_cbs_type_jpeg,#endif#if CONFIG_CBS_MPEG2    &ff_cbs_type_mpeg2,#endif#if CONFIG_CBS_VP8    &ff_cbs_type_vp8,#endif#if CONFIG_CBS_VP9    &ff_cbs_type_vp9,#endif}; const enum AVCodecID ff_cbs_all_codec_ids[] = {#if CONFIG_CBS_AV1    AV_CODEC_ID_AV1,#endif#if CONFIG_CBS_H264    AV_CODEC_ID_H264,#endif#if CONFIG_CBS_H265    AV_CODEC_ID_H265,#endif#if CONFIG_CBS_H266    AV_CODEC_ID_H266,#endif#if CONFIG_CBS_JPEG    AV_CODEC_ID_MJPEG,#endif#if CONFIG_CBS_MPEG2    AV_CODEC_ID_MPEG2VIDEO,#endif#if CONFIG_CBS_VP8    AV_CODEC_ID_VP8,#endif#if CONFIG_CBS_VP9    AV_CODEC_ID_VP9,#endif    AV_CODEC_ID_NONE}; av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr,                        enum AVCodecID codec_id, void *log_ctx){    CodedBitstreamContext *ctx;    const CodedBitstreamType *type;    int i;     type = NULL;    for (i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) {        if (cbs_type_table[i]->codec_id == codec_id) {            type = cbs_type_table[i];            break;        }    }    if (!type)        return AVERROR(EINVAL);     ctx = av_mallocz(sizeof(*ctx));    if (!ctx)        return AVERROR(ENOMEM);     ctx->log_ctx = log_ctx;    ctx->codec   = type; /* Must be before any error */     if (type->priv_data_size) {        ctx->priv_data = av_mallocz(ctx->codec->priv_data_size);        if (!ctx->priv_data) {            av_freep(&ctx);            return AVERROR(ENOMEM);        }        if (type->priv_class) {            *(const AVClass **)ctx->priv_data = type->priv_class;            av_opt_set_defaults(ctx->priv_data);        }    }     ctx->decompose_unit_types = NULL;     ctx->trace_enable  = 0;    ctx->trace_level   = AV_LOG_TRACE;    ctx->trace_context = ctx;     *ctx_ptr = ctx;    return 0;} av_cold void ff_cbs_flush(CodedBitstreamContext *ctx){    if (ctx->codec->flush)        ctx->codec->flush(ctx);} av_cold void ff_cbs_close(CodedBitstreamContext **ctx_ptr){    CodedBitstreamContext *ctx = *ctx_ptr;     if (!ctx)        return;     if (ctx->codec->close)        ctx->codec->close(ctx);     av_freep(&ctx->write_buffer);     if (ctx->codec->priv_class && ctx->priv_data)        av_opt_free(ctx->priv_data);     av_freep(&ctx->priv_data);    av_freep(ctx_ptr);} static void cbs_unit_uninit(CodedBitstreamUnit *unit){    av_refstruct_unref(&unit->content_ref);    unit->content = NULL;     av_buffer_unref(&unit->data_ref);    unit->data             = NULL;    unit->data_size        = 0;    unit->data_bit_padding = 0;} void ff_cbs_fragment_reset(CodedBitstreamFragment *frag){    int i;     for (i = 0; i < frag->nb_units; i++)        cbs_unit_uninit(&frag->units[i]);    frag->nb_units = 0;     av_buffer_unref(&frag->data_ref);    frag->data             = NULL;    frag->data_size        = 0;    frag->data_bit_padding = 0;} av_cold void ff_cbs_fragment_free(CodedBitstreamFragment *frag){    ff_cbs_fragment_reset(frag);     av_freep(&frag->units);    frag->nb_units_allocated = 0;} static int cbs_read_fragment_content(CodedBitstreamContext *ctx,                                     CodedBitstreamFragment *frag){    int err, i, j;     for (i = 0; i < frag->nb_units; i++) {        CodedBitstreamUnit *unit = &frag->units[i];         if (ctx->decompose_unit_types) {            for (j = 0; j < ctx->nb_decompose_unit_types; j++) {                if (ctx->decompose_unit_types[j] == unit->type)                    break;            }            if (j >= ctx->nb_decompose_unit_types)                continue;        }         av_refstruct_unref(&unit->content_ref);        unit->content = NULL;         av_assert0(unit->data && unit->data_ref);         err = ctx->codec->read_unit(ctx, unit);        if (err == AVERROR(ENOSYS)) {            av_log(ctx->log_ctx, AV_LOG_VERBOSE,                   "Decomposition unimplemented for unit %d "                   "(type %"PRIu32").\n", i, unit->type);        } else if (err == AVERROR(EAGAIN)) {            av_log(ctx->log_ctx, AV_LOG_VERBOSE,                   "Skipping decomposition of unit %d "                   "(type %"PRIu32").\n", i, unit->type);            av_refstruct_unref(&unit->content_ref);            unit->content = NULL;        } else if (err < 0) {            av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d "                   "(type %"PRIu32").\n", i, unit->type);            return err;        }    }     return 0;} static int cbs_fill_fragment_data(CodedBitstreamFragment *frag,                                  const uint8_t *data, size_t size){    av_assert0(!frag->data && !frag->data_ref);     frag->data_ref =        av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE);    if (!frag->data_ref)        return AVERROR(ENOMEM);     frag->data      = frag->data_ref->data;    frag->data_size = size;     memcpy(frag->data, data, size);    memset(frag->data + size, 0,           AV_INPUT_BUFFER_PADDING_SIZE);     return 0;} static int cbs_read_data(CodedBitstreamContext *ctx,                         CodedBitstreamFragment *frag,                         AVBufferRef *buf,                         const uint8_t *data, size_t size,                         int header){    int err;     if (buf) {        frag->data_ref = av_buffer_ref(buf);        if (!frag->data_ref)            return AVERROR(ENOMEM);         frag->data      = (uint8_t *)data;        frag->data_size = size;     } else {        err = cbs_fill_fragment_data(frag, data, size);        if (err < 0)            return err;    }     err = ctx->codec->split_fragment(ctx, frag, header);    if (err < 0)        return err;     return cbs_read_fragment_content(ctx, frag);} int ff_cbs_read_extradata(CodedBitstreamContext *ctx,                          CodedBitstreamFragment *frag,                          const AVCodecParameters *par){    return cbs_read_data(ctx, frag, NULL,                         par->extradata,                         par->extradata_size, 1);} int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx,                                     CodedBitstreamFragment *frag,                                     const AVCodecContext *avctx){    return cbs_read_data(ctx, frag, NULL,                         avctx->extradata,                         avctx->extradata_size, 1);} int ff_cbs_read_packet(CodedBitstreamContext *ctx,                       CodedBitstreamFragment *frag,                       const AVPacket *pkt){    return cbs_read_data(ctx, frag, pkt->buf,                         pkt->data, pkt->size, 0);} int ff_cbs_read_packet_side_data(CodedBitstreamContext *ctx,                                 CodedBitstreamFragment *frag,                                 const AVPacket *pkt){    size_t side_data_size;    const uint8_t *side_data =        av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,                                &side_data_size);     return cbs_read_data(ctx, frag, NULL,                         side_data, side_data_size, 1);} int ff_cbs_read(CodedBitstreamContext *ctx,                CodedBitstreamFragment *frag,                const uint8_t *data, size_t size){    return cbs_read_data(ctx, frag, NULL,                         data, size, 0);} /** * Allocate a new internal data buffer of the given size in the unit. * * The data buffer will have input padding. */static int cbs_alloc_unit_data(CodedBitstreamUnit *unit,                               size_t size){    av_assert0(!unit->data && !unit->data_ref);     unit->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE);    if (!unit->data_ref)        return AVERROR(ENOMEM);     unit->data      = unit->data_ref->data;    unit->data_size = size;     memset(unit->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);     return 0;} static int cbs_write_unit_data(CodedBitstreamContext *ctx,                               CodedBitstreamUnit *unit){    PutBitContext pbc;    int ret;     if (!ctx->write_buffer) {        // Initial write buffer size is 1MB.        ctx->write_buffer_size = 1024 * 1024;     reallocate_and_try_again:        ret = av_reallocp(&ctx->write_buffer, ctx->write_buffer_size);        if (ret < 0) {            av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a "                   "sufficiently large write buffer (last attempt "                   "%"SIZE_SPECIFIER" bytes).\n", ctx->write_buffer_size);            return ret;        }    }     init_put_bits(&pbc, ctx->write_buffer, ctx->write_buffer_size);     ret = ctx->codec->write_unit(ctx, unit, &pbc);    if (ret < 0) {        if (ret == AVERROR(ENOSPC)) {            // Overflow.            if (ctx->write_buffer_size == INT_MAX / 8)                return AVERROR(ENOMEM);            ctx->write_buffer_size = FFMIN(2 * ctx->write_buffer_size, INT_MAX / 8);            goto reallocate_and_try_again;        }        // Write failed for some other reason.        return ret;    }     // Overflow but we didn't notice.    av_assert0(put_bits_count(&pbc) <= 8 * ctx->write_buffer_size);     if (put_bits_count(&pbc) % 8)        unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8;    else        unit->data_bit_padding = 0;     flush_put_bits(&pbc);     ret = cbs_alloc_unit_data(unit, put_bytes_output(&pbc));    if (ret < 0)        return ret;     memcpy(unit->data, ctx->write_buffer, unit->data_size);     return 0;} int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx,                               CodedBitstreamFragment *frag){    int err, i;     for (i = 0; i < frag->nb_units; i++) {        CodedBitstreamUnit *unit = &frag->units[i];         if (!unit->content)            continue;         av_buffer_unref(&unit->data_ref);        unit->data = NULL;         err = cbs_write_unit_data(ctx, unit);        if (err < 0) {            av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d "                   "(type %"PRIu32").\n", i, unit->type);            return err;        }        av_assert0(unit->data && unit->data_ref);    }     av_buffer_unref(&frag->data_ref);    frag->data = NULL;     err = ctx->codec->assemble_fragment(ctx, frag);    if (err < 0) {        av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n");        return err;    }    av_assert0(frag->data && frag->data_ref);     return 0;} int ff_cbs_write_extradata(CodedBitstreamContext *ctx,                           AVCodecParameters *par,                           CodedBitstreamFragment *frag){    int err;     err = ff_cbs_write_fragment_data(ctx, frag);    if (err < 0)        return err;     av_freep(&par->extradata);    par->extradata_size = 0;     if (!frag->data_size)        return 0;     par->extradata = av_malloc(frag->data_size +                               AV_INPUT_BUFFER_PADDING_SIZE);    if (!par->extradata)        return AVERROR(ENOMEM);     memcpy(par->extradata, frag->data, frag->data_size);    memset(par->extradata + frag->data_size, 0,           AV_INPUT_BUFFER_PADDING_SIZE);    par->extradata_size = frag->data_size;     return 0;} int ff_cbs_write_packet(CodedBitstreamContext *ctx,                        AVPacket *pkt,                        CodedBitstreamFragment *frag){    AVBufferRef *buf;    int err;     err = ff_cbs_write_fragment_data(ctx, frag);    if (err < 0)        return err;     buf = av_buffer_ref(frag->data_ref);    if (!buf)        return AVERROR(ENOMEM);     av_buffer_unref(&pkt->buf);     pkt->buf  = buf;    pkt->data = frag->data;    pkt->size = frag->data_size;     return 0;}  void ff_cbs_trace_header(CodedBitstreamContext *ctx,                         const char *name)

Lines 1–500 of 1080.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t