[FFmpeg-devel] [PATCH 23/26] lavc/cbs: Add JPEG support
James Almer
jamrial at gmail.com
Tue Apr 24 05:16:27 EEST 2018
On 4/22/2018 12:29 PM, Mark Thompson wrote:
> +static int cbs_jpeg_split_fragment(CodedBitstreamContext *ctx,
> + CodedBitstreamFragment *frag,
> + int header)
> +{
> + uint8_t *unit_data;
> + size_t unit_size;
> + int unit, start, end, marker, next_start, next_marker;
> + int err, i, j;
> +
> + 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 {
> + int length;
> + i = start;
> + if (i + 2 > frag->data_size)
> + break;
> + length = frag->data[i] << 8 | frag->data[i + 1];
> + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Length = %d (i = %d)\n", length, i);
> + if (i + length > frag->data_size)
> + break;
> + 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;
> + }
> + }
> + }
> +
> + av_log(ctx->log_ctx, AV_LOG_DEBUG, "start = %d, end = %d, marker = %02x\n",
> + start, end, marker);
> +
> + unit_size = end - start;
> + unit_data = av_malloc(unit_size + AV_INPUT_BUFFER_PADDING_SIZE);
> + if (!unit_data)
> + return AVERROR(ENOMEM);
> + if (marker == JPEG_MARKER_SOS) {
> + for (i = start, j = 0; i < end; i++, j++) {
> + if (frag->data[i] == 0xff) {
> + while (frag->data[i] == 0xff)
> + ++i;
> + unit_data[j] = 0xff;
> + } else {
> + unit_data[j] = frag->data[i];
> + }
> + }
> + unit_size = j;
> + } else {
> + memcpy(unit_data, frag->data + start, unit_size);
Create a new frag->data_ref reference instead in this case. There's no
need to allocate a new buffer for these units.
> + }
> + memset(unit_data + unit_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
> +
> + err = ff_cbs_insert_unit_data(ctx, frag, unit, marker,
> + unit_data, unit_size, NULL);
> + if (err < 0) {
> + av_free(&unit_data);
> + return err;
> + }
> +
> + if (next_marker == -1)
> + break;
> + marker = next_marker;
> + start = next_start;
> + }
> +
> + 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) {
> + for (sp = 0; sp < unit->data_size; sp++)
> + data[dp++] = unit->data[sp];
memcpy(data + dp, unit->data, unit->data_size);
dp += unit->data_size;
Will probably be faster on big units.
> + } else {
> + for (sp = 0; 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;
> +}
More information about the ffmpeg-devel
mailing list