190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber/*
2f71323e297a928af368937089d3ed71239786f86Andreas Huber *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *
4f71323e297a928af368937089d3ed71239786f86Andreas Huber *  Use of this source code is governed by a BSD-style license
5f71323e297a928af368937089d3ed71239786f86Andreas Huber *  that can be found in the LICENSE file in the root of the source
6f71323e297a928af368937089d3ed71239786f86Andreas Huber *  tree. An additional intellectual property rights grant can be found
7f71323e297a928af368937089d3ed71239786f86Andreas Huber *  in the file PATENTS.  All contributing project authors may
8f71323e297a928af368937089d3ed71239786f86Andreas Huber *  be found in the AUTHORS file in the root of the source tree.
990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber */
1090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
1190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
1290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber/*
1390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@*INTRODUCTION
1490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber */
1590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#include <stdio.h>
1690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#include <stdlib.h>
1790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#include <stdarg.h>
1890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#include <string.h>
1990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#define VPX_CODEC_DISABLE_COMPAT 1
20f71323e297a928af368937089d3ed71239786f86Andreas Huber#include "vpx/vpx_encoder.h"
21f71323e297a928af368937089d3ed71239786f86Andreas Huber#include "vpx/vp8cx.h"
2279f15823c34ae1e423108295e416213200bb280fAndreas Huber#define interface (vpx_codec_vp8_cx())
2390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#define fourcc    0x30385056
2490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@EXTRA_INCLUDES
2590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
2690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#define IVF_FILE_HDR_SZ  (32)
2790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#define IVF_FRAME_HDR_SZ (12)
2890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
2990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic void mem_put_le16(char *mem, unsigned int val) {
3090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem[0] = val;
3190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem[1] = val>>8;
3290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber}
3390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
3490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic void mem_put_le32(char *mem, unsigned int val) {
3590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem[0] = val;
3690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem[1] = val>>8;
3790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem[2] = val>>16;
3890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem[3] = val>>24;
3990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber}
4090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
4190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic void die(const char *fmt, ...) {
4290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    va_list ap;
4390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
4490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    va_start(ap, fmt);
4590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    vprintf(fmt, ap);
4690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    if(fmt[strlen(fmt)-1] != '\n')
4790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        printf("\n");
4890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    exit(EXIT_FAILURE);
4990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber}
5090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
5190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@DIE_CODEC
5290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
5390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int read_frame(FILE *f, vpx_image_t *img) {
5490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    size_t nbytes, to_read;
5590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    int    res = 1;
5690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
5790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    to_read = img->w*img->h*3/2;
5890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    nbytes = fread(img->planes[0], 1, to_read, f);
5990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    if(nbytes != to_read) {
6090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        res = 0;
6190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        if(nbytes > 0)
6290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber            printf("Warning: Read partial frame. Check your width & height!\n");
6390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    }
6490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    return res;
6590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber}
6690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
6790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic void write_ivf_file_header(FILE *outfile,
6890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                                  const vpx_codec_enc_cfg_t *cfg,
6990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                                  int frame_cnt) {
7090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    char header[32];
7190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
7290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
7390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        return;
7490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    header[0] = 'D';
7590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    header[1] = 'K';
7690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    header[2] = 'I';
7790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    header[3] = 'F';
7890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le16(header+4,  0);                   /* version */
7990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le16(header+6,  32);                  /* headersize */
8090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le32(header+8,  fourcc);              /* headersize */
8190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le16(header+12, cfg->g_w);            /* width */
8290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le16(header+14, cfg->g_h);            /* height */
8390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
8490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
8590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le32(header+24, frame_cnt);           /* length */
8690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le32(header+28, 0);                   /* unused */
8790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
88538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if(fwrite(header, 1, 32, outfile));
8990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber}
9090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
9190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
9290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic void write_ivf_frame_header(FILE *outfile,
9390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                                   const vpx_codec_cx_pkt_t *pkt)
9490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{
9590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    char             header[12];
9690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    vpx_codec_pts_t  pts;
9790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
9890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
9990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        return;
10090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
10190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    pts = pkt->data.frame.pts;
10290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le32(header, pkt->data.frame.sz);
10390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le32(header+4, pts&0xFFFFFFFF);
10490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    mem_put_le32(header+8, pts >> 32);
10590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
106538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if(fwrite(header, 1, 12, outfile));
10790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber}
10890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
10990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberint main(int argc, char **argv) {
11090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    FILE                *infile, *outfile;
11190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    vpx_codec_ctx_t      codec;
11290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    vpx_codec_enc_cfg_t  cfg;
11390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    int                  frame_cnt = 0;
11490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    unsigned char        file_hdr[IVF_FILE_HDR_SZ];
11590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    unsigned char        frame_hdr[IVF_FRAME_HDR_SZ];
11690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    vpx_image_t          raw;
11790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    vpx_codec_err_t      res;
11890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    long                 width;
11990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    long                 height;
12090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    int                  frame_avail;
12190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    int                  got_data;
12290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    int                  flags = 0;
12390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@TWOPASS_VARS
12490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
12590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    /* Open files */
12690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@USAGE
12790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    width = strtol(argv[1], NULL, 0);
12890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    height = strtol(argv[2], NULL, 0);
12990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    if(width < 16 || width%2 || height <16 || height%2)
13090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        die("Invalid resolution: %ldx%ld", width, height);
131f71323e297a928af368937089d3ed71239786f86Andreas Huber    if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1))
13290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        die("Faile to allocate image", width, height);
13390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    if(!(outfile = fopen(argv[4], "wb")))
13490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        die("Failed to open %s for writing", argv[4]);
13590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
13690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    printf("Using %s\n",vpx_codec_iface_name(interface));
13790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
13890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@ENC_DEF_CFG
13990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
14090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@ENC_SET_CFG
14190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@ENC_SET_CFG2
14290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
14390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    write_ivf_file_header(outfile, &cfg, 0);
14490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
14590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@TWOPASS_LOOP_BEGIN
14690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
14790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        /* Open input file for this encoding pass */
14890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        if(!(infile = fopen(argv[3], "rb")))
14990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber            die("Failed to open %s for reading", argv[3]);
15090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
15190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@@@@@ENC_INIT
15290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
15390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        frame_avail = 1;
15490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        got_data = 0;
15590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        while(frame_avail || got_data) {
15690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber            vpx_codec_iter_t iter = NULL;
15790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber            const vpx_codec_cx_pkt_t *pkt;
15890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
15990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@@@@@@@@@PER_FRAME_CFG
16090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@@@@@@@@@ENCODE_FRAME
16190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber            got_data = 0;
16290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber            while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
16390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                got_data = 1;
16490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                switch(pkt->kind) {
16590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@@@@@@@@@@@@@PROCESS_FRAME
16690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@@@@@@@@@@@@@PROCESS_STATS
16790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                default:
16890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                    break;
16990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                }
17090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT
17190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                       && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
17290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber                fflush(stdout);
17390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber            }
17490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber            frame_cnt++;
17590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        }
17690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        printf("\n");
17790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        fclose(infile);
17890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@TWOPASS_LOOP_END
17990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
18090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    printf("Processed %d frames.\n",frame_cnt-1);
18190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber@@@@DESTROY
18290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber
18390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    /* Try to rewrite the file header with the actual frame count */
18490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    if(!fseek(outfile, 0, SEEK_SET))
18590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber        write_ivf_file_header(outfile, &cfg, frame_cnt-1);
18690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    fclose(outfile);
18790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber    return EXIT_SUCCESS;
18890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber}
189