On Fri, 2018-06-08 at 00:43 +0100, Mark Thompson wrote: > --- > configure | 2 + > libavcodec/Makefile | 1 + > libavcodec/cbs.c | 6 + > libavcodec/cbs_internal.h | 1 + > libavcodec/cbs_jpeg.c | 513 > ++++++++++++++++++++++++++++++++++ > libavcodec/cbs_jpeg.h | 128 +++++++++ > libavcodec/cbs_jpeg_syntax_template.c | 191 +++++++++++++ > 7 files changed, 842 insertions(+) > create mode 100644 libavcodec/cbs_jpeg.c > create mode 100644 libavcodec/cbs_jpeg.h > create mode 100644 libavcodec/cbs_jpeg_syntax_template.c > > diff --git a/configure b/configure > index 790f55be14..d908283954 100755 > --- a/configure > +++ b/configure > @@ -2244,6 +2244,7 @@ CONFIG_EXTRA=" > cbs > cbs_h264 > cbs_h265 > + cbs_jpeg > cbs_mpeg2 > cbs_vp9 > dirac_parse > @@ -2507,6 +2508,7 @@ threads_if_any="$THREADS_LIST" > # subsystems > cbs_h264_select="cbs golomb" > cbs_h265_select="cbs golomb" > +cbs_jpeg_select="cbs" > cbs_mpeg2_select="cbs" > cbs_vp9_select="cbs" > dct_select="rdft" > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index 3ab071a039..2a1e0de110 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -64,6 +64,7 @@ OBJS-$(CONFIG_CABAC) += cabac.o > OBJS-$(CONFIG_CBS) += cbs.o > OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o h2645_parse.o > OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o h2645_parse.o > +OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o > OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o > OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o > OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o > diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c > index be6c043b58..bb3ce95971 100644 > --- a/libavcodec/cbs.c > +++ b/libavcodec/cbs.c > @@ -35,6 +35,9 @@ static const CodedBitstreamType *cbs_type_table[] = { > #if CONFIG_CBS_H265 > &ff_cbs_type_h265, > #endif > +#if CONFIG_CBS_JPEG > + &ff_cbs_type_jpeg, > +#endif > #if CONFIG_CBS_MPEG2 > &ff_cbs_type_mpeg2, > #endif > @@ -50,6 +53,9 @@ const enum AVCodecID ff_cbs_all_codec_ids[] = { > #if CONFIG_CBS_H265 > AV_CODEC_ID_H265, > #endif > +#if CONFIG_CBS_JPEG > + AV_CODEC_ID_MJPEG, > +#endif > #if CONFIG_CBS_MPEG2 > AV_CODEC_ID_MPEG2VIDEO, > #endif > diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h > index 172b8a2515..e0e912e28e 100644 > --- a/libavcodec/cbs_internal.h > +++ b/libavcodec/cbs_internal.h > @@ -88,6 +88,7 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, > PutBitContext *pbc, > > extern const CodedBitstreamType ff_cbs_type_h264; > extern const CodedBitstreamType ff_cbs_type_h265; > +extern const CodedBitstreamType ff_cbs_type_jpeg; > extern const CodedBitstreamType ff_cbs_type_mpeg2; > extern const CodedBitstreamType ff_cbs_type_vp9; > > diff --git a/libavcodec/cbs_jpeg.c b/libavcodec/cbs_jpeg.c > new file mode 100644 > index 0000000000..365db73394 > --- /dev/null > +++ b/libavcodec/cbs_jpeg.c > @@ -0,0 +1,513 @@ > +/* > + * 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 "cbs.h" > +#include "cbs_internal.h" > +#include "cbs_jpeg.h" > + > + > +#define HEADER(name) do { \ > + ff_cbs_trace_header(ctx, name); \ > + } while (0) > + > +#define CHECK(call) do { \ > + err = (call); \ > + if (err < 0) \ > + return err; \ > + } while (0) > + > +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ > }) : NULL) > + > +#define u(width, name, range_min, range_max) \ > + xu(width, name, range_min, range_max, 0) > +#define us(width, name, sub, range_min, range_max) \ > + xu(width, name, range_min, range_max, 1, sub) > + > + > +#define READ > +#define READWRITE read > +#define RWContext GetBitContext > +#define FUNC(name) cbs_jpeg_read_ ## name > + > +#define xu(width, name, range_min, range_max, subs, ...) do { \ > + uint32_t value = range_min; \ > + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ > + SUBSCRIPTS(subs, __VA_ARGS__), \ > + &value, range_min, range_max)); \ > + current->name = value; \ > + } while (0) > + > +#include "cbs_jpeg_syntax_template.c" > + > +#undef READ > +#undef READWRITE > +#undef RWContext > +#undef FUNC > +#undef xu > + > +#define WRITE > +#define READWRITE write > +#define RWContext PutBitContext > +#define FUNC(name) cbs_jpeg_write_ ## name > + > +#define xu(width, name, range_min, range_max, subs, ...) do { \ > + uint32_t value = current->name; \ > + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ > + SUBSCRIPTS(subs, __VA_ARGS__), \ > + value, range_min, range_max)); \ > + } while (0) > + > + > +#include "cbs_jpeg_syntax_template.c" > + > +#undef READ > +#undef READWRITE > +#undef RWContext > +#undef FUNC > +#undef xu > + > + > +static void cbs_jpeg_free_application_data(void *unit, uint8_t *content) > +{ > + JPEGRawApplicationData *ad = (JPEGRawApplicationData*)content; > + av_buffer_unref(&ad->Ap_ref); > + av_freep(&content); > +} > + > +static void cbs_jpeg_free_scan(void *unit, uint8_t *content) > +{ > + JPEGRawScan *scan = (JPEGRawScan*)content; > + av_buffer_unref(&scan->data_ref); > + av_freep(&content); > +} > + > +static int cbs_jpeg_split_fragment(CodedBitstreamContext *ctx, > + CodedBitstreamFragment *frag, > + int header) > +{ > + AVBufferRef *data_ref; > + uint8_t *data; > + size_t data_size; > + int unit, start, end, marker, next_start, next_marker; > + int err, i, j, length; > + > + if (frag->data_size < 4) { > + // Definitely too short to be meaningful. > + return AVERROR_INVALIDDATA; > + } > + > + for (i = 0; i + 1 < frag->data_size && frag->data[i] != 0xff; i++); > + if (i > 0) { > + av_log(ctx->log_ctx, AV_LOG_WARNING, "Discarding %d bytes at " > + "beginning of image.\n", i); > + } > + for (++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++); > + if (i + 1 >= frag->data_size && frag->data[i]) { > + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " > + "no SOI marker found.\n"); > + return AVERROR_INVALIDDATA; > + } > + marker = frag->data[i]; > + if (marker != JPEG_MARKER_SOI) { > + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: first " > + "marker is %02x, should be SOI.\n", marker); > + return AVERROR_INVALIDDATA; > + } > + for (++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++); > + if (i + 1 >= frag->data_size) { > + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " > + "no image content found.\n"); > + return AVERROR_INVALIDDATA; > + } > + marker = frag->data[i]; > + start = i + 1; > + > + for (unit = 0;; unit++) { > + if (marker == JPEG_MARKER_EOI) { > + break; > + } else if (marker == JPEG_MARKER_SOS) { > + for (i = start; i + 1 < frag->data_size; i++) { > + if (frag->data[i] != 0xff) > + continue; > + end = i; > + for (++i; i + 1 < frag->data_size && > + frag->data[i] == 0xff; i++); > + if (i + 1 >= frag->data_size) { > + next_marker = -1; > + } else { > + if (frag->data[i] == 0x00) > + continue; > + next_marker = frag->data[i]; > + next_start = i + 1; > + } > + break; > + } > + } else { > + i = start; > + if (i + 2 > frag->data_size) { > + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " > + "truncated at %02x marker.\n", marker); > + return AVERROR_INVALIDDATA; > + } > + length = AV_RB16(frag->data + i); > + if (i + length > frag->data_size) { > + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " > + "truncated at %02x marker segment.\n", marker); > + return AVERROR_INVALIDDATA; > + } > + end = start + length; > + > + i = end; > + if (frag->data[i] != 0xff) { > + next_marker = -1; > + } else { > + for (++i; i + 1 < frag->data_size && > + frag->data[i] == 0xff; i++); > + if (i + 1 >= frag->data_size) { > + next_marker = -1; > + } else { > + next_marker = frag->data[i]; > + next_start = i + 1; > + } > + } > + } > + > + if (marker == JPEG_MARKER_SOS) { > + length = AV_RB16(frag->data + start); > + > + data_ref = NULL; > + data = av_malloc(end - start + > + AV_INPUT_BUFFER_PADDING_SIZE); > + if (!data) > + return AVERROR(ENOMEM); > + > + memcpy(data, frag->data + start, length); > + for (i = start + length, j = length; i < end; i++, j++) { > + if (frag->data[i] == 0xff) { > + while (frag->data[i] == 0xff) > + ++i; > + data[j] = 0xff; > + } else { > + data[j] = frag->data[i]; > + } > + } > + data_size = j; > + > + memset(data + data_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); > + > + } else { > + data = frag->data + start; > + data_size = end - start; > + data_ref = frag->data_ref; > + } > + > + err = ff_cbs_insert_unit_data(ctx, frag, unit, marker, > + data, data_size, data_ref); > + if (err < 0) { > + if (!data_ref) > + av_freep(&data); > + return err; > + } > + > + if (next_marker == -1) > + break; > + marker = next_marker; > + start = next_start; > + } > + > + return 0; > +} > + > +static int cbs_jpeg_read_unit(CodedBitstreamContext *ctx, > + CodedBitstreamUnit *unit) > +{ > + GetBitContext gbc; > + int err; > + > + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); > + if (err < 0) > + return err; > + > + if (unit->type >= JPEG_MARKER_SOF0 && > + unit->type <= JPEG_MARKER_SOF3) { > + err = ff_cbs_alloc_unit_content(ctx, unit, > + sizeof(JPEGRawFrameHeader), > + NULL); > + if (err < 0) > + return err; > + > + err = cbs_jpeg_read_frame_header(ctx, &gbc, unit->content); > + if (err < 0) > + return err; > + > + } else if (unit->type >= JPEG_MARKER_APPN && > + unit->type <= JPEG_MARKER_APPN + 15) { > + err = ff_cbs_alloc_unit_content(ctx, unit, > + sizeof(JPEGRawApplicationData), > + &cbs_jpeg_free_application_data); > + if (err < 0) > + return err; > + > + err = cbs_jpeg_read_application_data(ctx, &gbc, unit->content); > + if (err < 0) > + return err; > + > + } else if (unit->type == JPEG_MARKER_SOS) { > + JPEGRawScan *scan; > + int pos; > + > + err = ff_cbs_alloc_unit_content(ctx, unit, > + sizeof(JPEGRawScan), > + &cbs_jpeg_free_scan); > + if (err < 0) > + return err; > + scan = unit->content; > + > + err = cbs_jpeg_read_scan_header(ctx, &gbc, &scan->header); > + if (err < 0) > + return err; > + > + pos = get_bits_count(&gbc); > + av_assert0(pos % 8 == 0); > + if (pos > 0) { > + scan->data_size = unit->data_size - pos / 8; > + scan->data_ref = av_buffer_ref(unit->data_ref); > + if (!scan->data_ref) > + return AVERROR(ENOMEM); > + scan->data = unit->data + pos / 8; > + } > + > + } else { > + switch (unit->type) { > +#define SEGMENT(marker, type, func) \ > + case JPEG_MARKER_ ## marker: \ > + { \ > + err = ff_cbs_alloc_unit_content(ctx, unit, \ > + sizeof(type), NULL); \ > + if (err < 0) \ > + return err; \ > + err = cbs_jpeg_read_ ## func(ctx, &gbc, unit->content); \ > + if (err < 0) \ > + return err; \ > + } \ > + break > + SEGMENT(DQT, JPEGRawQuantisationTableSpecification, dqt); > + SEGMENT(DHT, JPEGRawHuffmanTableSpecification, dht); > + SEGMENT(COM, JPEGRawComment, comment);
A free function should be provided for JPEGRawComment as JPEGRawComment includes a AVBufferRef pointer. > +#undef SEGMENT > + default: > + return AVERROR(ENOSYS); > + } > + } > + > + return 0; > +} > + > +static int cbs_jpeg_write_scan(CodedBitstreamContext *ctx, > + CodedBitstreamUnit *unit, > + PutBitContext *pbc) > +{ > + JPEGRawScan *scan = unit->content; > + int i, err; > + > + err = cbs_jpeg_write_scan_header(ctx, pbc, &scan->header); > + if (err < 0) > + return err; > + > + if (scan->data) { > + if (scan->data_size * 8 > put_bits_left(pbc)) > + return AVERROR(ENOSPC); > + > + for (i = 0; i < scan->data_size; i++) > + put_bits(pbc, 8, scan->data[i]); > + } > + > + return 0; > +} > + > +static int cbs_jpeg_write_segment(CodedBitstreamContext *ctx, > + CodedBitstreamUnit *unit, > + PutBitContext *pbc) > +{ > + int err; > + > + if (unit->type >= JPEG_MARKER_SOF0 && > + unit->type <= JPEG_MARKER_SOF3) { > + err = cbs_jpeg_write_frame_header(ctx, pbc, unit->content); > + } else if (unit->type >= JPEG_MARKER_APPN && > + unit->type <= JPEG_MARKER_APPN + 15) { > + err = cbs_jpeg_write_application_data(ctx, pbc, unit->content); > + } else { > + switch (unit->type) { > +#define SEGMENT(marker, func) \ > + case JPEG_MARKER_ ## marker: \ > + err = cbs_jpeg_write_ ## func(ctx, pbc, unit->content); \ > + break; > + SEGMENT(DQT, dqt); > + SEGMENT(DHT, dht); > + SEGMENT(COM, comment); > + default: > + return AVERROR_PATCHWELCOME; > + } > + } > + > + return err; > +} > + > +static int cbs_jpeg_write_unit(CodedBitstreamContext *ctx, > + CodedBitstreamUnit *unit) > +{ > + CodedBitstreamJPEGContext *priv = ctx->priv_data; > + PutBitContext pbc; > + int err; > + > + if (!priv->write_buffer) { > + // Initial write buffer size is 1MB. > + priv->write_buffer_size = 1024 * 1024; > + > + reallocate_and_try_again: > + err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); > + if (err < 0) { > + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " > + "sufficiently large write buffer (last attempt " > + "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); > + return err; > + } > + } > + > + init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); > + > + if (unit->type == JPEG_MARKER_SOS) > + err = cbs_jpeg_write_scan(ctx, unit, &pbc); > + else > + err = cbs_jpeg_write_segment(ctx, unit, &pbc); > + > + if (err == AVERROR(ENOSPC)) { > + // Overflow. > + priv->write_buffer_size *= 2; > + goto reallocate_and_try_again; > + } > + if (err < 0) { > + // Write failed for some other reason. > + return err; > + } > + > + if (put_bits_count(&pbc) % 8) > + unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; > + else > + unit->data_bit_padding = 0; > + > + unit->data_size = (put_bits_count(&pbc) + 7) / 8; > + flush_put_bits(&pbc); > + > + err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); > + if (err < 0) > + return err; > + > + memcpy(unit->data, priv->write_buffer, unit->data_size); > + > + return 0; > +} > + > +static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, > + CodedBitstreamFragment *frag) > +{ > + const CodedBitstreamUnit *unit; > + uint8_t *data; > + size_t size, dp, sp; > + int i; > + > + size = 4; // SOI + EOI. > + for (i = 0; i < frag->nb_units; i++) { > + unit = &frag->units[i]; > + size += 2 + unit->data_size; > + if (unit->type == JPEG_MARKER_SOS) { > + for (sp = 0; sp < unit->data_size; sp++) { > + if (unit->data[sp] == 0xff) > + ++size; > + } > + } > + } > + > + frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); > + if (!frag->data_ref) > + return AVERROR(ENOMEM); > + data = frag->data_ref->data; > + > + dp = 0; > + > + data[dp++] = 0xff; > + data[dp++] = JPEG_MARKER_SOI; > + > + for (i = 0; i < frag->nb_units; i++) { > + unit = &frag->units[i]; > + > + data[dp++] = 0xff; > + data[dp++] = unit->type; > + > + if (unit->type != JPEG_MARKER_SOS) { > + memcpy(data + dp, unit->data, unit->data_size); > + dp += unit->data_size; > + } else { > + sp = AV_RB16(unit->data); > + av_assert0(sp <= unit->data_size); > + memcpy(data + dp, unit->data, sp); > + dp += sp; > + > + for (; sp < unit->data_size; sp++) { > + if (unit->data[sp] == 0xff) { > + data[dp++] = 0xff; > + data[dp++] = 0x00; > + } else { > + data[dp++] = unit->data[sp]; > + } > + } > + } > + } > + > + data[dp++] = 0xff; > + data[dp++] = JPEG_MARKER_EOI; > + > + av_assert0(dp == size); > + > + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); > + frag->data = data; > + frag->data_size = size; > + > + return 0; > +} > + > +static void cbs_jpeg_close(CodedBitstreamContext *ctx) > +{ > + CodedBitstreamJPEGContext *priv = ctx->priv_data; > + > + av_freep(&priv->write_buffer); > +} > + > +const CodedBitstreamType ff_cbs_type_jpeg = { > + .codec_id = AV_CODEC_ID_MJPEG, > + > + .priv_data_size = sizeof(CodedBitstreamJPEGContext), > + > + .split_fragment = &cbs_jpeg_split_fragment, > + .read_unit = &cbs_jpeg_read_unit, > + .write_unit = &cbs_jpeg_write_unit, > + .assemble_fragment = &cbs_jpeg_assemble_fragment, > + > + .close = &cbs_jpeg_close, > +}; > diff --git a/libavcodec/cbs_jpeg.h b/libavcodec/cbs_jpeg.h > new file mode 100644 > index 0000000000..f427c4c616 > --- /dev/null > +++ b/libavcodec/cbs_jpeg.h > @@ -0,0 +1,128 @@ > +/* > + * 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 AVCODEC_CBS_JPEG_H > +#define AVCODEC_CBS_JPEG_H > + > +#include <stddef.h> > +#include <stdint.h> > + > + > +enum { > + JPEG_MARKER_SOF0 = 0xc0, > + JPEG_MARKER_SOF1 = 0xc1, > + JPEG_MARKER_SOF2 = 0xc2, > + JPEG_MARKER_SOF3 = 0xc3, > + > + JPEG_MARKER_DHT = 0xc4, > + JPEG_MARKER_SOI = 0xd8, > + JPEG_MARKER_EOI = 0xd9, > + JPEG_MARKER_SOS = 0xda, > + JPEG_MARKER_DQT = 0xdb, > + > + JPEG_MARKER_APPN = 0xe0, > + JPEG_MARKER_JPGN = 0xf0, > + JPEG_MARKER_COM = 0xfe, > +}; > + > +enum { > + JPEG_MAX_COMPONENTS = 255, > + > + JPEG_MAX_HEIGHT = 65535, > + JPEG_MAX_WIDTH = 65535, > +}; > + > + > +typedef struct JPEGRawFrameHeader { > + uint16_t Lf; > + uint8_t P; > + uint16_t Y; > + uint16_t X; > + uint16_t Nf; > + > + uint8_t C [JPEG_MAX_COMPONENTS]; > + uint8_t H [JPEG_MAX_COMPONENTS]; > + uint8_t V [JPEG_MAX_COMPONENTS]; > + uint8_t Tq[JPEG_MAX_COMPONENTS]; > +} JPEGRawFrameHeader; > + > +typedef struct JPEGRawScanHeader { > + uint16_t Ls; > + uint8_t Ns; > + > + uint8_t Cs[JPEG_MAX_COMPONENTS]; > + uint8_t Td[JPEG_MAX_COMPONENTS]; > + uint8_t Ta[JPEG_MAX_COMPONENTS]; > + > + uint8_t Ss; > + uint8_t Se; > + uint8_t Ah; > + uint8_t Al; > +} JPEGRawScanHeader; > + > +typedef struct JPEGRawScan { > + JPEGRawScanHeader header; > + uint8_t *data; > + size_t data_size; > + AVBufferRef *data_ref; > +} JPEGRawScan; > + > +typedef struct JPEGRawQuantisationTable { > + uint8_t Pq; > + uint8_t Tq; > + uint16_t Q[64]; > +} JPEGRawQuantisationTable; > + > +typedef struct JPEGRawQuantisationTableSpecification { > + uint16_t Lq; > + JPEGRawQuantisationTable table[4]; > +} JPEGRawQuantisationTableSpecification; > + > +typedef struct JPEGRawHuffmanTable { > + uint8_t Tc; > + uint8_t Th; > + uint8_t L[16]; > + uint8_t V[224]; > +} JPEGRawHuffmanTable; > + > +typedef struct JPEGRawHuffmanTableSpecification { > + uint16_t Lh; > + JPEGRawHuffmanTable table[8]; > +} JPEGRawHuffmanTableSpecification; > + > +typedef struct JPEGRawApplicationData { > + uint16_t Lp; > + uint8_t *Ap; > + AVBufferRef *Ap_ref; > +} JPEGRawApplicationData; > + > +typedef struct JPEGRawComment { > + uint16_t Lc; > + uint8_t *Cm; > + AVBufferRef *Cm_ref; > +} JPEGRawComment; > + > + > +typedef struct CodedBitstreamJPEGContext { > + // Write buffer. > + uint8_t *write_buffer; > + size_t write_buffer_size; > +} CodedBitstreamJPEGContext; > + > + > +#endif /* AVCODEC_CBS_JPEG_H */ > diff --git a/libavcodec/cbs_jpeg_syntax_template.c > b/libavcodec/cbs_jpeg_syntax_template.c > new file mode 100644 > index 0000000000..d3cd9ff62e > --- /dev/null > +++ b/libavcodec/cbs_jpeg_syntax_template.c > @@ -0,0 +1,191 @@ > +/* > + * 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 > + */ > + > +static int FUNC(frame_header)(CodedBitstreamContext *ctx, RWContext *rw, > + JPEGRawFrameHeader *current) > +{ > + int err, i; > + > + HEADER("Frame Header"); > + > + u(16, Lf, 8, 8 + 3 * JPEG_MAX_COMPONENTS); > + > + u(8, P, 2, 16); > + u(16, Y, 0, JPEG_MAX_HEIGHT); > + u(16, X, 1, JPEG_MAX_WIDTH); > + u(8, Nf, 1, JPEG_MAX_COMPONENTS); > + > + for (i = 0; i < current->Nf; i++) { > + us(8, C[i], i, 0, JPEG_MAX_COMPONENTS); > + us(4, H[i], i, 1, 4); > + us(4, V[i], i, 1, 4); > + us(8, Tq[i], i, 0, 3); > + } > + > + return 0; > +} > + > +static int FUNC(quantisation_table)(CodedBitstreamContext *ctx, RWContext > *rw, > + JPEGRawQuantisationTable *current) > +{ > + int err, i; > + > + u(4, Pq, 0, 1); > + u(4, Tq, 0, 3); > + > + if (current->Pq) { > + for (i = 0; i < 64; i++) > + us(16, Q[i], i, 1, 255); > + } else { > + for (i = 0; i < 64; i++) > + us(8, Q[i], i, 1, 255); > + } > + > + return 0; > +} > + > +static int FUNC(dqt)(CodedBitstreamContext *ctx, RWContext *rw, > + JPEGRawQuantisationTableSpecification *current) > +{ > + int err, i, n; > + > + HEADER("Quantisation Tables"); > + > + u(16, Lq, 2, 2 + 4 * 65); > + n = current->Lq / 65; > + > + for (i = 0; i < n; i++) > + CHECK(FUNC(quantisation_table)(ctx, rw, ¤t->table[i])); > + > + return 0; > +} > + > +static int FUNC(huffman_table)(CodedBitstreamContext *ctx, RWContext *rw, > + JPEGRawHuffmanTable *current) > +{ > + int err, i, j, ij; > + > + u(4, Tc, 0, 1); > + u(4, Th, 0, 3); > + > + for (i = 0; i < 16; i++) > + us(8, L[i], i, 0, 224); > + > + ij = 0; > + for (i = 0; i < 16; i++) { > + for (j = 0; j < current->L[i]; j++) { > + us(8, V[ij], ij, 0, 255); > + ++ij; > + } > + } > + > + return 0; > +} > + > +static int FUNC(dht)(CodedBitstreamContext *ctx, RWContext *rw, > + JPEGRawHuffmanTableSpecification *current) > +{ > + int err, i, j, n; > + > + HEADER("Huffman Tables"); > + > + u(16, Lh, 2, 2 + 8 * (1 + 16 + 256)); > + > + n = 2; > + for (i = 0; n < current->Lh; i++) { > + CHECK(FUNC(huffman_table)(ctx, rw, ¤t->table[i])); > + > + ++n; > + for (j = 0; j < 16; j++) > + n += 1 + current->table[i].L[j]; > + } > + > + return 0; > +} > + > +static int FUNC(scan_header)(CodedBitstreamContext *ctx, RWContext *rw, > + JPEGRawScanHeader *current) > +{ > + int err, j; > + > + HEADER("Scan"); > + > + u(16, Ls, 6, 6 + 2 * JPEG_MAX_COMPONENTS); > + > + u(8, Ns, 1, 4); > + for (j = 0; j < current->Ns; j++) { > + us(8, Cs[j], j, 0, JPEG_MAX_COMPONENTS); > + us(4, Td[j], j, 0, 3); > + us(4, Ta[j], j, 0, 3); > + } > + > + u(8, Ss, 0, 63); > + u(8, Se, 0, 63); > + u(4, Ah, 0, 13); > + u(4, Al, 0, 15); > + > + return 0; > +} > + > +static int FUNC(application_data)(CodedBitstreamContext *ctx, RWContext *rw, > + JPEGRawApplicationData *current) > +{ > + int err, i; > + > + HEADER("Application Data"); > + > + u(16, Lp, 2, 65535); > + > + if (current->Lp > 2) { > +#ifdef READ > + current->Ap_ref = av_buffer_alloc(current->Lp - 2); > + if (!current->Ap_ref) > + return AVERROR(ENOMEM); > + current->Ap = current->Ap_ref->data; > +#endif > + > + for (i = 0; i < current->Lp - 2; i++) > + us(8, Ap[i], i, 0, 255); > + } > + > + return 0; > +} > + > +static int FUNC(comment)(CodedBitstreamContext *ctx, RWContext *rw, > + JPEGRawComment *current) > +{ > + int err, i; > + > + HEADER("Comment"); > + > + u(16, Lc, 2, 65535); > + > + if (current->Lc > 2) { > +#ifdef READ > + current->Cm_ref = av_buffer_alloc(current->Lc - 2); > + if (!current->Cm_ref) > + return AVERROR(ENOMEM); > + current->Cm = current->Cm_ref->data; > +#endif > + > + for (i = 0; i < current->Lc - 2; i++) > + us(8, Cm[i], i, 0, 255); > + } > + > + return 0; > +} _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel