Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / third_party / libvpx / source / libvpx / examples / force_keyframe.c
1 /*
2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 // Forcing A Keyframe
12 // ==================
13 //
14 // This is an example demonstrating how to control placement of keyframes
15 // on a frame-by-frame basis.
16 //
17 // Configuration
18 // -------------
19 // Keyframes can be forced by setting the VPX_EFLAG_FORCE_KF bit of the
20 // flags passed to `vpx_codec_control()`. In this example, we force a
21 // keyframe every 8 frames.
22 //
23 // Observing The Effects
24 // ---------------------
25 // The output of the encoder examples shows a 'K' rather than a dot '.'
26 // when the encoder generates a keyframe. Note that every 8 frames a 'K'
27 // is output.
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #define VPX_CODEC_DISABLE_COMPAT 1
34 #include "vpx/vpx_encoder.h"
35 #include "vpx/vp8cx.h"
36 #define interface (vpx_codec_vp8_cx())
37 #define fourcc    0x30385056
38
39 #define IVF_FILE_HDR_SZ  (32)
40 #define IVF_FRAME_HDR_SZ (12)
41
42 static void mem_put_le16(char *mem, unsigned int val) {
43     mem[0] = val;
44     mem[1] = val>>8;
45 }
46
47 static void mem_put_le32(char *mem, unsigned int val) {
48     mem[0] = val;
49     mem[1] = val>>8;
50     mem[2] = val>>16;
51     mem[3] = val>>24;
52 }
53
54 static void die(const char *fmt, ...) {
55     va_list ap;
56
57     va_start(ap, fmt);
58     vprintf(fmt, ap);
59     if(fmt[strlen(fmt)-1] != '\n')
60         printf("\n");
61     exit(EXIT_FAILURE);
62 }
63
64 static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
65     const char *detail = vpx_codec_error_detail(ctx);
66
67     printf("%s: %s\n", s, vpx_codec_error(ctx));
68     if(detail)
69         printf("    %s\n",detail);
70     exit(EXIT_FAILURE);
71 }
72
73 static int read_frame(FILE *f, vpx_image_t *img) {
74     size_t nbytes, to_read;
75     int    res = 1;
76
77     to_read = img->w*img->h*3/2;
78     nbytes = fread(img->planes[0], 1, to_read, f);
79     if(nbytes != to_read) {
80         res = 0;
81         if(nbytes > 0)
82             printf("Warning: Read partial frame. Check your width & height!\n");
83     }
84     return res;
85 }
86
87 static void write_ivf_file_header(FILE *outfile,
88                                   const vpx_codec_enc_cfg_t *cfg,
89                                   int frame_cnt) {
90     char header[32];
91
92     if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
93         return;
94     header[0] = 'D';
95     header[1] = 'K';
96     header[2] = 'I';
97     header[3] = 'F';
98     mem_put_le16(header+4,  0);                   /* version */
99     mem_put_le16(header+6,  32);                  /* headersize */
100     mem_put_le32(header+8,  fourcc);              /* headersize */
101     mem_put_le16(header+12, cfg->g_w);            /* width */
102     mem_put_le16(header+14, cfg->g_h);            /* height */
103     mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
104     mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
105     mem_put_le32(header+24, frame_cnt);           /* length */
106     mem_put_le32(header+28, 0);                   /* unused */
107
108     (void) fwrite(header, 1, 32, outfile);
109 }
110
111
112 static void write_ivf_frame_header(FILE *outfile,
113                                    const vpx_codec_cx_pkt_t *pkt)
114 {
115     char             header[12];
116     vpx_codec_pts_t  pts;
117
118     if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
119         return;
120
121     pts = pkt->data.frame.pts;
122     mem_put_le32(header, (unsigned int)pkt->data.frame.sz);
123     mem_put_le32(header+4, pts&0xFFFFFFFF);
124     mem_put_le32(header+8, pts >> 32);
125
126     (void) fwrite(header, 1, 12, outfile);
127 }
128
129 int main(int argc, char **argv) {
130     FILE                *infile, *outfile;
131     vpx_codec_ctx_t      codec;
132     vpx_codec_enc_cfg_t  cfg;
133     int                  frame_cnt = 0;
134     vpx_image_t          raw;
135     vpx_codec_err_t      res;
136     long                 width;
137     long                 height;
138     int                  frame_avail;
139     int                  got_data;
140     int                  flags = 0;
141
142     /* Open files */
143     if(argc!=5)
144         die("Usage: %s <width> <height> <infile> <outfile>\n", argv[0]);
145     width = strtol(argv[1], NULL, 0);
146     height = strtol(argv[2], NULL, 0);
147     if(width < 16 || width%2 || height <16 || height%2)
148         die("Invalid resolution: %ldx%ld", width, height);
149     if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1))
150         die("Faile to allocate image", width, height);
151     if(!(outfile = fopen(argv[4], "wb")))
152         die("Failed to open %s for writing", argv[4]);
153
154     printf("Using %s\n",vpx_codec_iface_name(interface));
155
156     /* Populate encoder configuration */
157     res = vpx_codec_enc_config_default(interface, &cfg, 0);
158     if(res) {
159         printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
160         return EXIT_FAILURE;
161     }
162
163     /* Update the default configuration with our settings */
164     cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate
165                             / cfg.g_w / cfg.g_h;
166     cfg.g_w = width;
167     cfg.g_h = height;
168
169     write_ivf_file_header(outfile, &cfg, 0);
170
171
172         /* Open input file for this encoding pass */
173         if(!(infile = fopen(argv[3], "rb")))
174             die("Failed to open %s for reading", argv[3]);
175
176         /* Initialize codec */
177         if(vpx_codec_enc_init(&codec, interface, &cfg, 0))
178             die_codec(&codec, "Failed to initialize encoder");
179
180         frame_avail = 1;
181         got_data = 0;
182         while(frame_avail || got_data) {
183             vpx_codec_iter_t iter = NULL;
184             const vpx_codec_cx_pkt_t *pkt;
185
186             if(!(frame_cnt & 7))
187                 flags |= VPX_EFLAG_FORCE_KF;
188             else
189                 flags &= ~VPX_EFLAG_FORCE_KF;
190             frame_avail = read_frame(infile, &raw);
191             if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt,
192                                 1, flags, VPX_DL_REALTIME))
193                 die_codec(&codec, "Failed to encode frame");
194             got_data = 0;
195             while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
196                 got_data = 1;
197                 switch(pkt->kind) {
198                 case VPX_CODEC_CX_FRAME_PKT:
199                     write_ivf_frame_header(outfile, pkt);
200                     (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
201                                   outfile);
202                     break;
203                 default:
204                     break;
205                 }
206                 printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT
207                        && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
208                 fflush(stdout);
209             }
210             frame_cnt++;
211         }
212         printf("\n");
213         fclose(infile);
214
215     printf("Processed %d frames.\n",frame_cnt-1);
216     vpx_img_free(&raw);
217     if(vpx_codec_destroy(&codec))
218         die_codec(&codec, "Failed to destroy codec");
219
220     /* Try to rewrite the file header with the actual frame count */
221     if(!fseek(outfile, 0, SEEK_SET))
222         write_ivf_file_header(outfile, &cfg, frame_cnt-1);
223     fclose(outfile);
224     return EXIT_SUCCESS;
225 }