#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ujpeg.h"
#include "scale.h"
#include "rgb2yuv.h"
#include "preview.h"
#include "encode.h"

#define OUTPUT_WIDTH   1280
#define OUTPUT_HEIGHT   720

#define FRAME_COUNT      50

#define START_CX        0.5f
#define START_CY        0.4f
#define START_ZOOM    (-1.0f)
#define END_CX          0.5f
#define END_CY          0.5f
#define END_ZOOM      (-1.5f)

int main(int argc, char *argv[]) {
    ujImage jpeg;
    static unsigned char rgbbuf[OUTPUT_WIDTH * OUTPUT_HEIGHT * 3];
    scale_image_struct s;
    int frameno;
    float t;
    encoder_frame_t frame;
    encoder_handle_t enc = NULL;
    rgb2yuv_matrix_t matrix;

    if (argc < 2) return 1;
    jpeg = ujDecodeFile(NULL, argv[1]);
    if (!jpeg || !ujGetImage(jpeg, NULL)) return 1;

    if (argc > 2) {
        encoder_config_t cfg;
        memset(&cfg, 0, sizeof(cfg));
        cfg.filename = argv[2];
        cfg.width = OUTPUT_WIDTH;
        cfg.height = OUTPUT_HEIGHT;
        cfg.flags = ENC_VERBOSE | ENC_BT709 | ENC_OPTIMAL_QUALITY;
        if (encode_init(&enc, &cfg))
            return 1;
    }

    frame.y.pixels = malloc(OUTPUT_WIDTH * OUTPUT_HEIGHT);
    frame.y.stride = OUTPUT_WIDTH;
    frame.cb.pixels = malloc(OUTPUT_WIDTH * OUTPUT_HEIGHT / 4);
    frame.cb.stride = OUTPUT_WIDTH / 2;
    frame.cr.pixels = malloc(OUTPUT_WIDTH * OUTPUT_HEIGHT / 4);
    frame.cr.stride = OUTPUT_WIDTH / 2;
    rgb2yuv_create_matrix(&matrix, REC709_MATRIX);
    preview_init(OUTPUT_WIDTH, OUTPUT_HEIGHT, 1);
    preview_title("test_output");

    for (frameno = 0;  frameno < FRAME_COUNT;  ++frameno) {
        t = frameno * (1.0f / (FRAME_COUNT - 1));
        printf("\rframe %d ...", frameno + 1);
        fflush(stdout);
        s.src = ujGetImage(jpeg, NULL);
        s.dest = rgbbuf;
        s.src_width = ujGetWidth(jpeg);
        s.src_height = ujGetHeight(jpeg);
        s.dest_width = OUTPUT_WIDTH;
        s.dest_height = OUTPUT_HEIGHT;
        s.src_pix_stride = ujIsColor(jpeg) ? 3 : 1;
        s.src_line_stride = s.src_pix_stride * s.src_width;
        s.dest_pix_stride = 3;
        s.dest_line_stride = 3 * OUTPUT_WIDTH;
        s.bpp = 3;
        s.flags = SF_USE_BORDER_COLOR;
        s.border_color = 0;
        scale_set_zoom(&s,
            START_CX + t * (END_CX - START_CX),
            START_CY + t * (END_CY - START_CY),
            1.0f, 0.5f, 0.5f, 1.0f,
            START_ZOOM + t * (END_ZOOM - START_ZOOM));
        if (!scale_image_ex(&s))
            return 1;
        if (preview_update(rgbbuf) == PREVIEW_BREAK)
            break;
        if (enc) {
            rgb2yuv_convert_interleaved_inplace(matrix, rgbbuf, OUTPUT_WIDTH * OUTPUT_HEIGHT);
            interleaved_channel_to_planar(&rgbbuf[1], frame.y.pixels,
                OUTPUT_WIDTH, OUTPUT_HEIGHT, 3, OUTPUT_WIDTH * 3, frame.y.stride);
            interleaved_channel_to_planar_2x2_mpeg(&rgbbuf[2], frame.cb.pixels,
                OUTPUT_WIDTH, OUTPUT_HEIGHT, 3, OUTPUT_WIDTH * 3, frame.cb.stride);
            interleaved_channel_to_planar_2x2_mpeg(&rgbbuf[0], frame.cr.pixels,
                OUTPUT_WIDTH, OUTPUT_HEIGHT, 3, OUTPUT_WIDTH * 3, frame.cr.stride);
            frame.flags = 0;
            encode_frame(enc, &frame);
        }
    }
    printf("\r%d frames rendered.\n", frameno);
    if (enc) {
        printf("average bitrate: %d kbps\n", encode_done(enc));
    }
    preview_done();
    ujFree(jpeg);
    return 0;
}

