*/
#include "avcodec.h"
-#include "dsputil.h"
#include "hpeldsp.h"
+#include "me_cmp.h"
#include "mpegvideo.h"
#include "h263.h"
#include "internal.h"
+#include "mpegutils.h"
#include "svq1.h"
+#include "svq1enc.h"
#include "svq1enc_cb.h"
#undef NDEBUG
#include <assert.h>
-typedef struct SVQ1Context {
- /* FIXME: Needed for motion estimation, should not be used for anything
- * else, the idea is to make the motion estimation eventually independent
- * of MpegEncContext, so this will be removed then. */
- MpegEncContext m;
- AVCodecContext *avctx;
- DSPContext dsp;
- HpelDSPContext hdsp;
- AVFrame *current_picture;
- AVFrame *last_picture;
- PutBitContext pb;
- GetBitContext gb;
-
- /* why ooh why this sick breadth first order,
- * everything is slower and more complex */
- PutBitContext reorder_pb[6];
-
- int frame_width;
- int frame_height;
-
- /* Y plane block dimensions */
- int y_block_width;
- int y_block_height;
-
- /* U & V plane (C planes) block dimensions */
- int c_block_width;
- int c_block_height;
-
- uint16_t *mb_type;
- uint32_t *dummy;
- int16_t (*motion_val8[3])[2];
- int16_t (*motion_val16[3])[2];
-
- int64_t rd_total;
-
- uint8_t *scratchbuf;
-} SVQ1Context;
-
-static void svq1_write_header(SVQ1Context *s, int frame_type)
+static void svq1_write_header(SVQ1EncContext *s, int frame_type)
{
int i;
#define QUALITY_THRESHOLD 100
#define THRESHOLD_MULTIPLIER 0.6
-static int encode_block(SVQ1Context *s, uint8_t *src, uint8_t *ref,
+static int ssd_int8_vs_int16_c(const int8_t *pix1, const int16_t *pix2,
+ int size)
+{
+ int score = 0, i;
+
+ for (i = 0; i < size; i++)
+ score += (pix1[i] - pix2[i]) * (pix1[i] - pix2[i]);
+ return score;
+}
+
+static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref,
uint8_t *decoded, int stride, int level,
int threshold, int lambda, int intra)
{
int sqr, diff, score;
vector = codebook + stage * size * 16 + i * size;
- sqr = s->dsp.ssd_int8_vs_int16(vector, block[stage], size);
+ sqr = s->ssd_int8_vs_int16(vector, block[stage], size);
diff = block_sum[stage] - sum;
score = sqr - (diff * (int64_t)diff >> (level + 3)); // FIXME: 64bit slooow
if (score < best_vector_score) {
return best_score;
}
-static int svq1_encode_plane(SVQ1Context *s, int plane,
+static int svq1_encode_plane(SVQ1EncContext *s, int plane,
unsigned char *src_plane,
unsigned char *ref_plane,
unsigned char *decoded_plane,
int width, int height, int src_stride, int stride)
{
- const AVFrame *f = s->avctx->coded_frame;
int x, y;
int i;
int block_width, block_height;
int level;
int threshold[6];
uint8_t *src = s->scratchbuf + stride * 16;
- const int lambda = (f->quality * f->quality) >>
+ const int lambda = (s->quality * s->quality) >>
(2 * FF_LAMBDA_SHIFT);
/* figure out the acceptable level thresholds in advance */
block_width = (width + 15) / 16;
block_height = (height + 15) / 16;
- if (f->pict_type == AV_PICTURE_TYPE_P) {
+ if (s->pict_type == AV_PICTURE_TYPE_P) {
s->m.avctx = s->avctx;
s->m.current_picture_ptr = &s->m.current_picture;
s->m.last_picture_ptr = &s->m.last_picture;
- s->m.last_picture.f.data[0] = ref_plane;
+ s->m.last_picture.f->data[0] = ref_plane;
s->m.linesize =
- s->m.last_picture.f.linesize[0] =
- s->m.new_picture.f.linesize[0] =
- s->m.current_picture.f.linesize[0] = stride;
+ s->m.last_picture.f->linesize[0] =
+ s->m.new_picture.f->linesize[0] =
+ s->m.current_picture.f->linesize[0] = stride;
s->m.width = width;
s->m.height = height;
s->m.mb_width = block_width;
s->m.mb_stride = s->m.mb_width + 1;
s->m.b8_stride = 2 * s->m.mb_width + 1;
s->m.f_code = 1;
- s->m.pict_type = f->pict_type;
+ s->m.pict_type = s->pict_type;
s->m.me_method = s->avctx->me_method;
s->m.me.scene_change_score = 0;
- s->m.flags = s->avctx->flags;
// s->m.out_format = FMT_H263;
// s->m.unrestricted_mv = 1;
- s->m.lambda = f->quality;
+ s->m.lambda = s->quality;
s->m.qscale = s->m.lambda * 139 +
FF_LAMBDA_SCALE * 64 >>
FF_LAMBDA_SHIFT + 7;
s->motion_val16[plane] = av_mallocz((s->m.mb_stride *
(block_height + 2) + 1) *
2 * sizeof(int16_t));
+ if (!s->motion_val8[plane] || !s->motion_val16[plane])
+ return AVERROR(ENOMEM);
}
s->m.mb_type = s->mb_type;
s->m.current_picture.motion_val[0] = s->motion_val8[plane] + 2;
s->m.p_mv_table = s->motion_val16[plane] +
s->m.mb_stride + 1;
- s->m.dsp = s->dsp; // move
+ s->m.mecc = s->mecc; // move
ff_init_me(&s->m);
s->m.me.dia_size = s->avctx->dia_size;
s->m.first_slice_line = 1;
for (y = 0; y < block_height; y++) {
- s->m.new_picture.f.data[0] = src - y * 16 * stride; // ugly
+ s->m.new_picture.f->data[0] = src - y * 16 * stride; // ugly
s->m.mb_y = y;
for (i = 0; i < 16 && i + 16 * y < height; i++) {
ff_init_block_index(&s->m);
ff_update_block_index(&s->m);
- if (f->pict_type == AV_PICTURE_TYPE_I ||
+ if (s->pict_type == AV_PICTURE_TYPE_I ||
(s->m.mb_type[x + y * s->m.mb_stride] &
CANDIDATE_MB_TYPE_INTRA)) {
for (i = 0; i < 6; i++)
init_put_bits(&s->reorder_pb[i], reorder_buffer[0][i],
7 * 32);
- if (f->pict_type == AV_PICTURE_TYPE_P) {
+ if (s->pict_type == AV_PICTURE_TYPE_P) {
const uint8_t *vlc = ff_svq1_block_type_vlc[SVQ1_BLOCK_INTRA];
put_bits(&s->reorder_pb[5], vlc[1], vlc[0]);
score[0] = vlc[1] * lambda;
best = 0;
- if (f->pict_type == AV_PICTURE_TYPE_P) {
+ if (s->pict_type == AV_PICTURE_TYPE_P) {
const uint8_t *vlc = ff_svq1_block_type_vlc[SVQ1_BLOCK_INTER];
int mx, my, pred_x, pred_y, dxy;
int16_t *motion_ptr;
best = score[1] <= score[0];
vlc = ff_svq1_block_type_vlc[SVQ1_BLOCK_SKIP];
- score[2] = s->dsp.sse[0](NULL, src + 16 * x, ref,
- stride, 16);
+ score[2] = s->mecc.sse[0](NULL, src + 16 * x, ref,
+ stride, 16);
score[2] += vlc[1] * lambda;
if (score[2] < score[best] && mx == 0 && my == 0) {
best = 2;
static av_cold int svq1_encode_end(AVCodecContext *avctx)
{
- SVQ1Context *const s = avctx->priv_data;
+ SVQ1EncContext *const s = avctx->priv_data;
int i;
av_log(avctx, AV_LOG_DEBUG, "RD: %f\n",
s->rd_total / (double)(avctx->width * avctx->height *
avctx->frame_number));
+ s->m.mb_type = NULL;
+ ff_mpv_common_end(&s->m);
+
av_freep(&s->m.me.scratchpad);
av_freep(&s->m.me.map);
av_freep(&s->m.me.score_map);
av_frame_free(&s->current_picture);
av_frame_free(&s->last_picture);
- av_frame_free(&avctx->coded_frame);
return 0;
}
static av_cold int svq1_encode_init(AVCodecContext *avctx)
{
- SVQ1Context *const s = avctx->priv_data;
+ SVQ1EncContext *const s = avctx->priv_data;
+ int ret;
- ff_dsputil_init(&s->dsp, avctx);
ff_hpeldsp_init(&s->hdsp, avctx->flags);
+ ff_me_cmp_init(&s->mecc, avctx);
+ ff_mpegvideoencdsp_init(&s->m.mpvencdsp, avctx);
- avctx->coded_frame = av_frame_alloc();
s->current_picture = av_frame_alloc();
s->last_picture = av_frame_alloc();
- if (!avctx->coded_frame || !s->current_picture || !s->last_picture) {
+ if (!s->current_picture || !s->last_picture) {
svq1_encode_end(avctx);
return AVERROR(ENOMEM);
}
s->avctx = avctx;
s->m.avctx = avctx;
+
+ if ((ret = ff_mpv_common_init(&s->m)) < 0) {
+ svq1_encode_end(avctx);
+ return ret;
+ }
+
s->m.picture_structure = PICT_FRAME;
s->m.me.temp =
s->m.me.scratchpad = av_mallocz((avctx->width + 64) *
s->y_block_height * sizeof(int16_t));
s->dummy = av_mallocz((s->y_block_width + 1) *
s->y_block_height * sizeof(int32_t));
+ s->ssd_int8_vs_int16 = ssd_int8_vs_int16_c;
+
+ if (!s->m.me.temp || !s->m.me.scratchpad || !s->m.me.map ||
+ !s->m.me.score_map || !s->mb_type || !s->dummy) {
+ svq1_encode_end(avctx);
+ return AVERROR(ENOMEM);
+ }
+
+ if (ARCH_PPC)
+ ff_svq1enc_init_ppc(s);
+ if (ARCH_X86)
+ ff_svq1enc_init_x86(s);
+
ff_h263_encode_init(&s->m); // mv_penalty
return 0;
static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pict, int *got_packet)
{
- SVQ1Context *const s = avctx->priv_data;
- AVFrame *const p = avctx->coded_frame;
+ SVQ1EncContext *const s = avctx->priv_data;
int i, ret;
+ uint8_t *sd;
if (!pkt->data &&
(ret = av_new_packet(pkt, s->y_block_width * s->y_block_height *
}
if (!s->current_picture->data[0]) {
- ff_get_buffer(avctx, s->current_picture, 0);
- ff_get_buffer(avctx, s->last_picture, 0);
+ ret = ff_get_buffer(avctx, s->current_picture, 0);
+ if (ret < 0)
+ return ret;
+ }
+ if (!s->last_picture->data[0]) {
+ ret = ff_get_buffer(avctx, s->last_picture, 0);
+ if (ret < 0)
+ return ret;
+ }
+ if (!s->scratchbuf) {
s->scratchbuf = av_malloc(s->current_picture->linesize[0] * 16 * 2);
+ if (!s->scratchbuf)
+ return AVERROR(ENOMEM);
}
FFSWAP(AVFrame*, s->current_picture, s->last_picture);
init_put_bits(&s->pb, pkt->data, pkt->size);
- p->pict_type = avctx->gop_size && avctx->frame_number % avctx->gop_size ?
- AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
- p->key_frame = p->pict_type == AV_PICTURE_TYPE_I;
- p->quality = pict->quality;
+ if (avctx->gop_size && (avctx->frame_number % avctx->gop_size))
+ s->pict_type = AV_PICTURE_TYPE_P;
+ else
+ s->pict_type = AV_PICTURE_TYPE_I;
+ s->quality = pict->quality;
+
+#if FF_API_CODED_FRAME
+FF_DISABLE_DEPRECATION_WARNINGS
+ avctx->coded_frame->pict_type = s->pict_type;
+ avctx->coded_frame->key_frame = s->pict_type == AV_PICTURE_TYPE_I;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+ sd = av_packet_new_side_data(pkt, AV_PKT_DATA_QUALITY_FACTOR, sizeof(int));
+ if (!sd)
+ return AVERROR(ENOMEM);
+ *(int *)sd = pict->quality;
- svq1_write_header(s, p->pict_type);
+ svq1_write_header(s, s->pict_type);
for (i = 0; i < 3; i++)
if (svq1_encode_plane(s, i,
pict->data[i],
s->frame_width / (i ? 4 : 1),
s->frame_height / (i ? 4 : 1),
pict->linesize[i],
- s->current_picture->linesize[i]) < 0)
+ s->current_picture->linesize[i]) < 0) {
+ int j;
+ for (j = 0; j < i; j++) {
+ av_freep(&s->motion_val8[j]);
+ av_freep(&s->motion_val16[j]);
+ }
+ av_freep(&s->scratchbuf);
return -1;
+ }
// avpriv_align_put_bits(&s->pb);
while (put_bits_count(&s->pb) & 31)
flush_put_bits(&s->pb);
pkt->size = put_bits_count(&s->pb) / 8;
- if (p->pict_type == AV_PICTURE_TYPE_I)
+ if (s->pict_type == AV_PICTURE_TYPE_I)
pkt->flags |= AV_PKT_FLAG_KEY;
*got_packet = 1;
.long_name = NULL_IF_CONFIG_SMALL("Sorenson Vector Quantizer 1 / Sorenson Video 1 / SVQ1"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_SVQ1,
- .priv_data_size = sizeof(SVQ1Context),
+ .priv_data_size = sizeof(SVQ1EncContext),
.init = svq1_encode_init,
.encode2 = svq1_encode_frame,
.close = svq1_encode_end,