1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00
FFmpeg/libavcodec/mjpegenc.c

316 lines
10 KiB
C
Raw Normal View History

/*
* MJPEG encoder
* Copyright (c) 2000, 2001 Fabrice Bellard
* Copyright (c) 2003 Alex Beregszaszi
* Copyright (c) 2003-2004 Michael Niedermayer
*
* Support for external huffman table, various fixes (AVID workaround),
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
* 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
* MJPEG encoder.
*/
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "jpegtables.h"
#include "mjpegenc_common.h"
#include "mpegvideo.h"
#include "mjpeg.h"
#include "mjpegenc.h"
static uint8_t uni_ac_vlc_len[64 * 64 * 2];
static uint8_t uni_chroma_ac_vlc_len[64 * 64 * 2];
static av_cold void init_uni_ac_vlc(const uint8_t huff_size_ac[256], uint8_t *uni_ac_vlc_len)
{
int i;
for (i = 0; i < 128; i++) {
int level = i - 64;
int run;
if (!level)
continue;
for (run = 0; run < 64; run++) {
int len, code, nbits;
int alevel = FFABS(level);
len = (run >> 4) * huff_size_ac[0xf0];
nbits= av_log2_16bit(alevel) + 1;
code = ((15&run) << 4) | nbits;
len += huff_size_ac[code] + nbits;
uni_ac_vlc_len[UNI_AC_ENC_INDEX(run, i)] = len;
// We ignore EOB as its just a constant which does not change generally
}
}
}
av_cold int ff_mjpeg_encode_init(MpegEncContext *s)
{
MJpegContext *m;
if (s->width > 65500 || s->height > 65500) {
av_log(s, AV_LOG_ERROR, "JPEG does not support resolutions above 65500x65500\n");
2013-12-29 12:54:32 +03:00
return AVERROR(EINVAL);
}
m = av_malloc(sizeof(MJpegContext));
if (!m)
2013-12-29 12:54:32 +03:00
return AVERROR(ENOMEM);
s->min_qcoeff=-1023;
s->max_qcoeff= 1023;
/* build all the huffman tables */
ff_mjpeg_build_huffman_codes(m->huff_size_dc_luminance,
m->huff_code_dc_luminance,
avpriv_mjpeg_bits_dc_luminance,
avpriv_mjpeg_val_dc);
ff_mjpeg_build_huffman_codes(m->huff_size_dc_chrominance,
m->huff_code_dc_chrominance,
avpriv_mjpeg_bits_dc_chrominance,
avpriv_mjpeg_val_dc);
ff_mjpeg_build_huffman_codes(m->huff_size_ac_luminance,
m->huff_code_ac_luminance,
avpriv_mjpeg_bits_ac_luminance,
avpriv_mjpeg_val_ac_luminance);
ff_mjpeg_build_huffman_codes(m->huff_size_ac_chrominance,
m->huff_code_ac_chrominance,
avpriv_mjpeg_bits_ac_chrominance,
avpriv_mjpeg_val_ac_chrominance);
init_uni_ac_vlc(m->huff_size_ac_luminance, uni_ac_vlc_len);
init_uni_ac_vlc(m->huff_size_ac_chrominance, uni_chroma_ac_vlc_len);
s->intra_ac_vlc_length =
s->intra_ac_vlc_last_length = uni_ac_vlc_len;
s->intra_chroma_ac_vlc_length =
s->intra_chroma_ac_vlc_last_length = uni_chroma_ac_vlc_len;
s->mjpeg_ctx = m;
return 0;
}
av_cold void ff_mjpeg_encode_close(MpegEncContext *s)
{
av_freep(&s->mjpeg_ctx);
}
static void encode_block(MpegEncContext *s, int16_t *block, int n)
{
int mant, nbits, code, i, j;
int component, dc, run, last_index, val;
MJpegContext *m = s->mjpeg_ctx;
uint8_t *huff_size_ac;
uint16_t *huff_code_ac;
/* DC coef */
component = (n <= 3 ? 0 : (n&1) + 1);
dc = block[0]; /* overflow is impossible */
val = dc - s->last_dc[component];
if (n < 4) {
ff_mjpeg_encode_dc(&s->pb, val, m->huff_size_dc_luminance, m->huff_code_dc_luminance);
huff_size_ac = m->huff_size_ac_luminance;
huff_code_ac = m->huff_code_ac_luminance;
} else {
ff_mjpeg_encode_dc(&s->pb, val, m->huff_size_dc_chrominance, m->huff_code_dc_chrominance);
huff_size_ac = m->huff_size_ac_chrominance;
huff_code_ac = m->huff_code_ac_chrominance;
}
s->last_dc[component] = dc;
/* AC coefs */
run = 0;
last_index = s->block_last_index[n];
for(i=1;i<=last_index;i++) {
j = s->intra_scantable.permutated[i];
val = block[j];
if (val == 0) {
run++;
} else {
while (run >= 16) {
put_bits(&s->pb, huff_size_ac[0xf0], huff_code_ac[0xf0]);
run -= 16;
}
mant = val;
if (val < 0) {
val = -val;
mant--;
}
nbits= av_log2_16bit(val) + 1;
code = (run << 4) | nbits;
put_bits(&s->pb, huff_size_ac[code], huff_code_ac[code]);
put_sbits(&s->pb, nbits, mant);
run = 0;
}
}
/* output EOB only if not already 64 values */
if (last_index < 63 || run != 0)
put_bits(&s->pb, huff_size_ac[0], huff_code_ac[0]);
}
void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[12][64])
{
int i;
if (s->chroma_format == CHROMA_444) {
encode_block(s, block[0], 0);
encode_block(s, block[2], 2);
encode_block(s, block[4], 4);
encode_block(s, block[8], 8);
encode_block(s, block[5], 5);
encode_block(s, block[9], 9);
if (16*s->mb_x+8 < s->width) {
encode_block(s, block[1], 1);
encode_block(s, block[3], 3);
encode_block(s, block[6], 6);
encode_block(s, block[10], 10);
encode_block(s, block[7], 7);
encode_block(s, block[11], 11);
}
} else {
for(i=0;i<5;i++) {
encode_block(s, block[i], i);
}
if (s->chroma_format == CHROMA_420) {
encode_block(s, block[5], 5);
} else {
encode_block(s, block[6], 6);
encode_block(s, block[5], 5);
encode_block(s, block[7], 7);
}
}
s->i_tex_bits += get_bits_diff(s);
}
// maximum over s->mjpeg_vsample[i]
#define V_MAX 2
static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pic_arg, int *got_packet)
{
MpegEncContext *s = avctx->priv_data;
AVFrame *pic;
int i, ret;
int chroma_h_shift, chroma_v_shift;
av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_h_shift, &chroma_v_shift);
#if FF_API_EMU_EDGE
//CODEC_FLAG_EMU_EDGE have to be cleared
if(s->avctx->flags & CODEC_FLAG_EMU_EDGE)
2013-12-29 12:54:32 +03:00
return AVERROR(EINVAL);
#endif
if ((avctx->height & 15) && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
av_log(avctx, AV_LOG_ERROR,
"Heights which are not a multiple of 16 might fail with some decoders, "
"use vstrict=-1 / -strict -1 to use %d anyway.\n", avctx->height);
av_log(avctx, AV_LOG_WARNING, "If you have a device that plays AMV videos, please test if videos "
"with such heights work with it and report your findings to ffmpeg-devel@ffmpeg.org\n");
return AVERROR_EXPERIMENTAL;
}
pic = av_frame_clone(pic_arg);
if (!pic)
return AVERROR(ENOMEM);
//picture should be flipped upside-down
for(i=0; i < 3; i++) {
int vsample = i ? 2 >> chroma_v_shift : 2;
pic->data[i] += pic->linesize[i] * (vsample * s->height / V_MAX - 1);
pic->linesize[i] *= -1;
}
ret = ff_mpv_encode_picture(avctx, pkt, pic, got_packet);
av_frame_free(&pic);
return ret;
}
#define OFFSET(x) offsetof(MpegEncContext, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
FF_MPV_COMMON_OPTS
{ "pred", "Prediction method", OFFSET(pred), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 3, VE, "pred" },
{ "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "pred" },
{ "plane", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "pred" },
{ "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 3 }, INT_MIN, INT_MAX, VE, "pred" },
{ NULL},
};
#if CONFIG_MJPEG_ENCODER
static const AVClass mjpeg_class = {
.class_name = "mjpeg encoder",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
AVCodec ff_mjpeg_encoder = {
.name = "mjpeg",
.long_name = NULL_IF_CONFIG_SMALL("MJPEG (Motion JPEG)"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_MJPEG,
.priv_data_size = sizeof(MpegEncContext),
.init = ff_mpv_encode_init,
.encode2 = ff_mpv_encode_picture,
.close = ff_mpv_encode_end,
.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY,
.pix_fmts = (const enum AVPixelFormat[]){
AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE
},
.priv_class = &mjpeg_class,
};
#endif
#if CONFIG_AMV_ENCODER
static const AVClass amv_class = {
.class_name = "amv encoder",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
AVCodec ff_amv_encoder = {
.name = "amv",
.long_name = NULL_IF_CONFIG_SMALL("AMV Video"),
.type = AVMEDIA_TYPE_VIDEO,
Merge commit '36ef5369ee9b336febc2c270f8718cec4476cb85' * commit '36ef5369ee9b336febc2c270f8718cec4476cb85': Replace all CODEC_ID_* with AV_CODEC_ID_* lavc: add AV prefix to codec ids. Conflicts: doc/APIchanges doc/examples/decoding_encoding.c doc/examples/muxing.c ffmpeg.c ffprobe.c ffserver.c libavcodec/8svx.c libavcodec/avcodec.h libavcodec/dnxhd_parser.c libavcodec/dvdsubdec.c libavcodec/error_resilience.c libavcodec/h263dec.c libavcodec/libvorbisenc.c libavcodec/mjpeg_parser.c libavcodec/mjpegenc.c libavcodec/mpeg12.c libavcodec/mpeg4videodec.c libavcodec/mpegvideo.c libavcodec/mpegvideo_enc.c libavcodec/pcm.c libavcodec/r210dec.c libavcodec/utils.c libavcodec/v210dec.c libavcodec/version.h libavdevice/alsa-audio-dec.c libavdevice/bktr.c libavdevice/v4l2.c libavformat/asfdec.c libavformat/asfenc.c libavformat/avformat.h libavformat/avidec.c libavformat/caf.c libavformat/electronicarts.c libavformat/flacdec.c libavformat/flvdec.c libavformat/flvenc.c libavformat/framecrcenc.c libavformat/img2.c libavformat/img2dec.c libavformat/img2enc.c libavformat/ipmovie.c libavformat/isom.c libavformat/matroska.c libavformat/matroskadec.c libavformat/matroskaenc.c libavformat/mov.c libavformat/movenc.c libavformat/mp3dec.c libavformat/mpeg.c libavformat/mpegts.c libavformat/mxf.c libavformat/mxfdec.c libavformat/mxfenc.c libavformat/nsvdec.c libavformat/nut.c libavformat/oggenc.c libavformat/pmpdec.c libavformat/rawdec.c libavformat/rawenc.c libavformat/riff.c libavformat/sdp.c libavformat/utils.c libavformat/vocenc.c libavformat/wtv.c libavformat/xmv.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
2012-08-07 23:45:46 +03:00
.id = AV_CODEC_ID_AMV,
.priv_data_size = sizeof(MpegEncContext),
.init = ff_mpv_encode_init,
.encode2 = amv_encode_picture,
.close = ff_mpv_encode_end,
Merge commit '716d413c13981da15323c7a3821860536eefdbbb' * commit '716d413c13981da15323c7a3821860536eefdbbb': Replace PIX_FMT_* -> AV_PIX_FMT_*, PixelFormat -> AVPixelFormat Conflicts: doc/examples/muxing.c ffmpeg.h ffmpeg_filter.c ffmpeg_opt.c ffplay.c ffprobe.c libavcodec/8bps.c libavcodec/aasc.c libavcodec/aura.c libavcodec/avcodec.h libavcodec/avs.c libavcodec/bfi.c libavcodec/bmp.c libavcodec/bmpenc.c libavcodec/c93.c libavcodec/cscd.c libavcodec/cyuv.c libavcodec/dpx.c libavcodec/dpxenc.c libavcodec/eatgv.c libavcodec/escape124.c libavcodec/ffv1.c libavcodec/flashsv.c libavcodec/fraps.c libavcodec/h264.c libavcodec/huffyuv.c libavcodec/iff.c libavcodec/imgconvert.c libavcodec/indeo3.c libavcodec/kmvc.c libavcodec/libopenjpegdec.c libavcodec/libopenjpegenc.c libavcodec/libx264.c libavcodec/ljpegenc.c libavcodec/mjpegdec.c libavcodec/mjpegenc.c libavcodec/motionpixels.c libavcodec/mpeg12.c libavcodec/mpeg12enc.c libavcodec/mpeg4videodec.c libavcodec/mpegvideo_enc.c libavcodec/pamenc.c libavcodec/pcxenc.c libavcodec/pgssubdec.c libavcodec/pngdec.c libavcodec/pngenc.c libavcodec/pnm.c libavcodec/pnmdec.c libavcodec/pnmenc.c libavcodec/ptx.c libavcodec/qdrw.c libavcodec/qpeg.c libavcodec/qtrleenc.c libavcodec/raw.c libavcodec/rawdec.c libavcodec/rl2.c libavcodec/sgidec.c libavcodec/sgienc.c libavcodec/snowdec.c libavcodec/snowenc.c libavcodec/sunrast.c libavcodec/targa.c libavcodec/targaenc.c libavcodec/tiff.c libavcodec/tiffenc.c libavcodec/tmv.c libavcodec/truemotion2.c libavcodec/utils.c libavcodec/vb.c libavcodec/vp3.c libavcodec/wnv1.c libavcodec/xl.c libavcodec/xwddec.c libavcodec/xwdenc.c libavcodec/yop.c libavdevice/v4l2.c libavdevice/x11grab.c libavfilter/avfilter.c libavfilter/avfilter.h libavfilter/buffersrc.c libavfilter/drawutils.c libavfilter/formats.c libavfilter/src_movie.c libavfilter/vf_ass.c libavfilter/vf_drawtext.c libavfilter/vf_fade.c libavfilter/vf_format.c libavfilter/vf_hflip.c libavfilter/vf_lut.c libavfilter/vf_overlay.c libavfilter/vf_pad.c libavfilter/vf_scale.c libavfilter/vf_transpose.c libavfilter/vf_yadif.c libavfilter/video.c libavfilter/vsrc_testsrc.c libavformat/movenc.c libavformat/mxf.h libavformat/utils.c libavformat/yuv4mpeg.c libavutil/imgutils.c libavutil/pixdesc.c libswscale/input.c libswscale/output.c libswscale/swscale_internal.h libswscale/swscale_unscaled.c libswscale/utils.c libswscale/x86/swscale_template.c libswscale/x86/yuv2rgb.c libswscale/x86/yuv2rgb_template.c libswscale/yuv2rgb.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
2012-10-08 21:54:00 +03:00
.pix_fmts = (const enum AVPixelFormat[]){
AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_NONE
},
.priv_class = &amv_class,
};
#endif