| OLD | NEW |
| (Empty) | |
| 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 // Simple Encoder |
| 12 // ============== |
| 13 // |
| 14 // This is an example of a simple encoder loop. It takes an input file in |
| 15 // YV12 format, passes it through the encoder, and writes the compressed |
| 16 // frames to disk in IVF format. Other decoder examples build upon this |
| 17 // one. |
| 18 // |
| 19 // The details of the IVF format have been elided from this example for |
| 20 // simplicity of presentation, as IVF files will not generally be used by |
| 21 // your application. In general, an IVF file consists of a file header, |
| 22 // followed by a variable number of frames. Each frame consists of a frame |
| 23 // header followed by a variable length payload. The length of the payload |
| 24 // is specified in the first four bytes of the frame header. The payload is |
| 25 // the raw compressed data. |
| 26 // |
| 27 // Standard Includes |
| 28 // ----------------- |
| 29 // For encoders, you only have to include `vpx_encoder.h` and then any |
| 30 // header files for the specific codecs you use. In this case, we're using |
| 31 // vp8. The `VPX_CODEC_DISABLE_COMPAT` macro can be defined to ensure |
| 32 // strict compliance with the latest SDK by disabling some backwards |
| 33 // compatibility features. Defining this macro is encouraged. |
| 34 // |
| 35 // Getting The Default Configuration |
| 36 // --------------------------------- |
| 37 // Encoders have the notion of "usage profiles." For example, an encoder |
| 38 // may want to publish default configurations for both a video |
| 39 // conferencing appliction and a best quality offline encoder. These |
| 40 // obviously have very different default settings. Consult the |
| 41 // documentation for your codec to see if it provides any default |
| 42 // configurations. All codecs provide a default configuration, number 0, |
| 43 // which is valid for material in the vacinity of QCIF/QVGA. |
| 44 // |
| 45 // Updating The Configuration |
| 46 // --------------------------------- |
| 47 // Almost all applications will want to update the default configuration |
| 48 // with settings specific to their usage. Here we set the width and height |
| 49 // of the video file to that specified on the command line. We also scale |
| 50 // the default bitrate based on the ratio between the default resolution |
| 51 // and the resolution specified on the command line. |
| 52 // |
| 53 // Initializing The Codec |
| 54 // ---------------------- |
| 55 // The encoder is initialized by the following code. |
| 56 // |
| 57 // Encoding A Frame |
| 58 // ---------------- |
| 59 // The frame is read as a continuous block (size width * height * 3 / 2) |
| 60 // from the input file. If a frame was read (the input file has not hit |
| 61 // EOF) then the frame is passed to the encoder. Otherwise, a NULL |
| 62 // is passed, indicating the End-Of-Stream condition to the encoder. The |
| 63 // `frame_cnt` is reused as the presentation time stamp (PTS) and each |
| 64 // frame is shown for one frame-time in duration. The flags parameter is |
| 65 // unused in this example. The deadline is set to VPX_DL_REALTIME to |
| 66 // make the example run as quickly as possible. |
| 67 // |
| 68 // Processing The Encoded Data |
| 69 // --------------------------- |
| 70 // Each packet of type `VPX_CODEC_CX_FRAME_PKT` contains the encoded data |
| 71 // for this frame. We write a IVF frame header, followed by the raw data. |
| 72 // |
| 73 // Cleanup |
| 74 // ------- |
| 75 // The `vpx_codec_destroy` call frees any memory allocated by the codec. |
| 76 // |
| 77 // Error Handling |
| 78 // -------------- |
| 79 // This example does not special case any error return codes. If there was |
| 80 // an error, a descriptive message is printed and the program exits. With |
| 81 // few exeptions, vpx_codec functions return an enumerated error status, |
| 82 // with the value `0` indicating success. |
| 83 |
| 84 #include <stdio.h> |
| 85 #include <stdlib.h> |
| 86 #include <stdarg.h> |
| 87 #include <string.h> |
| 88 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 89 #include "vpx/vpx_encoder.h" |
| 90 #include "vpx/vp8cx.h" |
| 91 #define interface (vpx_codec_vp8_cx()) |
| 92 #define fourcc 0x30385056 |
| 93 |
| 94 #define IVF_FILE_HDR_SZ (32) |
| 95 #define IVF_FRAME_HDR_SZ (12) |
| 96 |
| 97 static void mem_put_le16(char *mem, unsigned int val) { |
| 98 mem[0] = val; |
| 99 mem[1] = val>>8; |
| 100 } |
| 101 |
| 102 static void mem_put_le32(char *mem, unsigned int val) { |
| 103 mem[0] = val; |
| 104 mem[1] = val>>8; |
| 105 mem[2] = val>>16; |
| 106 mem[3] = val>>24; |
| 107 } |
| 108 |
| 109 static void die(const char *fmt, ...) { |
| 110 va_list ap; |
| 111 |
| 112 va_start(ap, fmt); |
| 113 vprintf(fmt, ap); |
| 114 if(fmt[strlen(fmt)-1] != '\n') |
| 115 printf("\n"); |
| 116 exit(EXIT_FAILURE); |
| 117 } |
| 118 |
| 119 static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { |
| 120 const char *detail = vpx_codec_error_detail(ctx); |
| 121 |
| 122 printf("%s: %s\n", s, vpx_codec_error(ctx)); |
| 123 if(detail) |
| 124 printf(" %s\n",detail); |
| 125 exit(EXIT_FAILURE); |
| 126 } |
| 127 |
| 128 static int read_frame(FILE *f, vpx_image_t *img) { |
| 129 size_t nbytes, to_read; |
| 130 int res = 1; |
| 131 |
| 132 to_read = img->w*img->h*3/2; |
| 133 nbytes = fread(img->planes[0], 1, to_read, f); |
| 134 if(nbytes != to_read) { |
| 135 res = 0; |
| 136 if(nbytes > 0) |
| 137 printf("Warning: Read partial frame. Check your width & height!\n"); |
| 138 } |
| 139 return res; |
| 140 } |
| 141 |
| 142 static void write_ivf_file_header(FILE *outfile, |
| 143 const vpx_codec_enc_cfg_t *cfg, |
| 144 int frame_cnt) { |
| 145 char header[32]; |
| 146 |
| 147 if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) |
| 148 return; |
| 149 header[0] = 'D'; |
| 150 header[1] = 'K'; |
| 151 header[2] = 'I'; |
| 152 header[3] = 'F'; |
| 153 mem_put_le16(header+4, 0); /* version */ |
| 154 mem_put_le16(header+6, 32); /* headersize */ |
| 155 mem_put_le32(header+8, fourcc); /* headersize */ |
| 156 mem_put_le16(header+12, cfg->g_w); /* width */ |
| 157 mem_put_le16(header+14, cfg->g_h); /* height */ |
| 158 mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ |
| 159 mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ |
| 160 mem_put_le32(header+24, frame_cnt); /* length */ |
| 161 mem_put_le32(header+28, 0); /* unused */ |
| 162 |
| 163 (void) fwrite(header, 1, 32, outfile); |
| 164 } |
| 165 |
| 166 |
| 167 static void write_ivf_frame_header(FILE *outfile, |
| 168 const vpx_codec_cx_pkt_t *pkt) |
| 169 { |
| 170 char header[12]; |
| 171 vpx_codec_pts_t pts; |
| 172 |
| 173 if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) |
| 174 return; |
| 175 |
| 176 pts = pkt->data.frame.pts; |
| 177 mem_put_le32(header, pkt->data.frame.sz); |
| 178 mem_put_le32(header+4, pts&0xFFFFFFFF); |
| 179 mem_put_le32(header+8, pts >> 32); |
| 180 |
| 181 (void) fwrite(header, 1, 12, outfile); |
| 182 } |
| 183 |
| 184 int main(int argc, char **argv) { |
| 185 FILE *infile, *outfile; |
| 186 vpx_codec_ctx_t codec; |
| 187 vpx_codec_enc_cfg_t cfg; |
| 188 int frame_cnt = 0; |
| 189 vpx_image_t raw; |
| 190 vpx_codec_err_t res; |
| 191 long width; |
| 192 long height; |
| 193 int frame_avail; |
| 194 int got_data; |
| 195 int flags = 0; |
| 196 |
| 197 /* Open files */ |
| 198 if(argc!=5) |
| 199 die("Usage: %s <width> <height> <infile> <outfile>\n", argv[0]); |
| 200 width = strtol(argv[1], NULL, 0); |
| 201 height = strtol(argv[2], NULL, 0); |
| 202 if(width < 16 || width%2 || height <16 || height%2) |
| 203 die("Invalid resolution: %ldx%ld", width, height); |
| 204 if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1)) |
| 205 die("Faile to allocate image", width, height); |
| 206 if(!(outfile = fopen(argv[4], "wb"))) |
| 207 die("Failed to open %s for writing", argv[4]); |
| 208 |
| 209 printf("Using %s\n",vpx_codec_iface_name(interface)); |
| 210 |
| 211 /* Populate encoder configuration */ |
| 212 res = vpx_codec_enc_config_default(interface, &cfg, 0); |
| 213 if(res) { |
| 214 printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); |
| 215 return EXIT_FAILURE; |
| 216 } |
| 217 |
| 218 /* Update the default configuration with our settings */ |
| 219 cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate |
| 220 / cfg.g_w / cfg.g_h; |
| 221 cfg.g_w = width; |
| 222 cfg.g_h = height; |
| 223 |
| 224 write_ivf_file_header(outfile, &cfg, 0); |
| 225 |
| 226 |
| 227 /* Open input file for this encoding pass */ |
| 228 if(!(infile = fopen(argv[3], "rb"))) |
| 229 die("Failed to open %s for reading", argv[3]); |
| 230 |
| 231 /* Initialize codec */ |
| 232 if(vpx_codec_enc_init(&codec, interface, &cfg, 0)) |
| 233 die_codec(&codec, "Failed to initialize encoder"); |
| 234 |
| 235 frame_avail = 1; |
| 236 got_data = 0; |
| 237 while(frame_avail || got_data) { |
| 238 vpx_codec_iter_t iter = NULL; |
| 239 const vpx_codec_cx_pkt_t *pkt; |
| 240 |
| 241 frame_avail = read_frame(infile, &raw); |
| 242 if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt, |
| 243 1, flags, VPX_DL_REALTIME)) |
| 244 die_codec(&codec, "Failed to encode frame"); |
| 245 got_data = 0; |
| 246 while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { |
| 247 got_data = 1; |
| 248 switch(pkt->kind) { |
| 249 case VPX_CODEC_CX_FRAME_PKT: |
| 250 write_ivf_frame_header(outfile, pkt); |
| 251 (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, |
| 252 outfile); |
| 253 break; |
| 254 default: |
| 255 break; |
| 256 } |
| 257 printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT |
| 258 && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); |
| 259 fflush(stdout); |
| 260 } |
| 261 frame_cnt++; |
| 262 } |
| 263 printf("\n"); |
| 264 fclose(infile); |
| 265 |
| 266 printf("Processed %d frames.\n",frame_cnt-1); |
| 267 vpx_img_free(&raw); |
| 268 if(vpx_codec_destroy(&codec)) |
| 269 die_codec(&codec, "Failed to destroy codec"); |
| 270 |
| 271 /* Try to rewrite the file header with the actual frame count */ |
| 272 if(!fseek(outfile, 0, SEEK_SET)) |
| 273 write_ivf_file_header(outfile, &cfg, frame_cnt-1); |
| 274 fclose(outfile); |
| 275 return EXIT_SUCCESS; |
| 276 } |
| OLD | NEW |